flapjack 0.6.38 → 0.6.39
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitmodules +3 -0
- data/.travis.yml +2 -0
- data/README.md +15 -186
- data/Rakefile +11 -7
- data/bin/flapjack +9 -17
- data/bin/flapjack-nagios-receiver +19 -32
- data/bin/flapjack-populator +7 -2
- data/etc/flapjack_config.yaml.example +20 -0
- data/flapjack.gemspec +1 -3
- data/lib/flapjack/api.rb +1 -5
- data/lib/flapjack/coordinator.rb +24 -28
- data/lib/flapjack/data/contact.rb +12 -10
- data/lib/flapjack/data/entity.rb +2 -2
- data/lib/flapjack/data/entity_check.rb +0 -9
- data/lib/flapjack/data/global.rb +25 -0
- data/lib/flapjack/executive.rb +1 -0
- data/lib/flapjack/jabber.rb +11 -19
- data/lib/flapjack/oobetet.rb +34 -32
- data/lib/flapjack/pagerduty.rb +140 -140
- data/lib/flapjack/redis_pool.rb +1 -1
- data/lib/flapjack/version.rb +1 -1
- data/lib/flapjack/web/views/check.haml +1 -1
- data/spec/lib/flapjack/coordinator_spec.rb +162 -5
- data/spec/lib/flapjack/data/contact_spec.rb +34 -2
- data/spec/lib/flapjack/data/entity_spec.rb +25 -11
- data/spec/lib/flapjack/jabber_spec.rb +2 -3
- data/spec/lib/flapjack/oobetet_spec.rb +140 -0
- data/spec/lib/flapjack/pagerduty_spec.rb +177 -0
- data/spec/lib/flapjack/redis_pool_spec.rb +24 -0
- data/spec/spec_helper.rb +3 -0
- metadata +10 -40
- data/doc/CONFIGURING.md +0 -38
- data/doc/DEBUGGING.md +0 -28
- data/doc/DEVELOPING.md +0 -35
- data/doc/GLOSSARY.md +0 -19
- data/doc/INSTALL.md +0 -64
- data/doc/PACKAGING.md +0 -25
data/lib/flapjack/pagerduty.rb
CHANGED
@@ -12,6 +12,7 @@ require 'redis'
|
|
12
12
|
require 'yajl/json_gem'
|
13
13
|
|
14
14
|
require 'flapjack/data/entity_check'
|
15
|
+
require 'flapjack/data/global'
|
15
16
|
require 'flapjack/pikelet'
|
16
17
|
|
17
18
|
module Flapjack
|
@@ -20,144 +21,13 @@ module Flapjack
|
|
20
21
|
|
21
22
|
include Flapjack::Pikelet
|
22
23
|
|
24
|
+
PAGERDUTY_EVENTS_API_URL = 'https://events.pagerduty.com/generic/2010-04-15/create_event.json'
|
25
|
+
SEM_PAGERDUTY_ACKS_RUNNING = 'sem_pagerduty_acks_running'
|
26
|
+
|
23
27
|
def setup
|
24
28
|
@redis = build_redis_connection_pool
|
25
29
|
logger.debug("New Pagerduty pikelet with the following options: #{@config.inspect}")
|
26
30
|
|
27
|
-
@pagerduty_events_api_url = 'https://events.pagerduty.com/generic/2010-04-15/create_event.json'
|
28
|
-
@pagerduty_acks_started = nil
|
29
|
-
@sem_pagerduty_acks_running = 'sem_pagerduty_acks_running'
|
30
|
-
end
|
31
|
-
|
32
|
-
def send_pagerduty_event(event)
|
33
|
-
options = { :body => Yajl::Encoder.encode(event) }
|
34
|
-
http = EM::HttpRequest.new(@pagerduty_events_api_url).post(options)
|
35
|
-
response = Yajl::Parser.parse(http.response)
|
36
|
-
status = http.response_header.status
|
37
|
-
logger.debug "send_pagerduty_event got a return code of #{status.to_s} - #{response.inspect}"
|
38
|
-
[status, response]
|
39
|
-
end
|
40
|
-
|
41
|
-
def test_pagerduty_connection
|
42
|
-
noop = { "service_key" => "11111111111111111111111111111111",
|
43
|
-
"incident_key" => "Flapjack is running a NOOP",
|
44
|
-
"event_type" => "nop",
|
45
|
-
"description" => "I love APIs with noops." }
|
46
|
-
code, results = send_pagerduty_event(noop)
|
47
|
-
return true if code == 200 && results['status'] =~ /success/i
|
48
|
-
logger.error "Error: test_pagerduty_connection: API returned #{code.to_s} #{results.inspect}"
|
49
|
-
false
|
50
|
-
end
|
51
|
-
|
52
|
-
# this should be moved to a checks data model perhaps
|
53
|
-
def unacknowledged_failing_checks
|
54
|
-
failing_checks = @redis_timer.zrange('failed_checks', '0', '-1')
|
55
|
-
unless failing_checks.is_a?(Array)
|
56
|
-
@logger.error("redis.zrange returned something other than an array! Here it is: " + failing_checks.inspect)
|
57
|
-
end
|
58
|
-
ufc = failing_checks.reject {|check|
|
59
|
-
@redis_timer.exists(check + ':unscheduled_maintenance')
|
60
|
-
}
|
61
|
-
@logger.debug "found unacknowledged failing checks as follows: " + ufc.join(', ')
|
62
|
-
ufc
|
63
|
-
end
|
64
|
-
|
65
|
-
def pagerduty_acknowledged?(opts)
|
66
|
-
subdomain = opts['subdomain']
|
67
|
-
username = opts['username']
|
68
|
-
password = opts['password']
|
69
|
-
check = opts['check']
|
70
|
-
|
71
|
-
url = 'https://' + subdomain + '.pagerduty.com/api/v1/incidents'
|
72
|
-
query = { 'fields' => 'incident_number,status,last_status_change_by',
|
73
|
-
'since' => (Time.new.utc - (60*60*24*7)).iso8601,
|
74
|
-
'until' => (Time.new.utc + (60*60*24)).iso8601,
|
75
|
-
'incident_key' => check,
|
76
|
-
'status' => 'acknowledged' }
|
77
|
-
|
78
|
-
options = { :head => { 'authorization' => [username, password] },
|
79
|
-
:query => query }
|
80
|
-
|
81
|
-
http = EM::HttpRequest.new(url).get(options)
|
82
|
-
# DEBUG flapjack-pagerduty: pagerduty_acknowledged?: decoded response as:
|
83
|
-
# {"incidents"=>[{"incident_number"=>40, "status"=>"acknowledged",
|
84
|
-
# "last_status_change_by"=>{"id"=>"PO1NWPS", "name"=>"Jesse Reynolds",
|
85
|
-
# "email"=>"jesse@bulletproof.net",
|
86
|
-
# "html_url"=>"http://bltprf.pagerduty.com/users/PO1NWPS"}}], "limit"=>100, "offset"=>0,
|
87
|
-
# "total"=>1}
|
88
|
-
begin
|
89
|
-
response = Yajl::Parser.parse(http.response)
|
90
|
-
rescue Yajl::ParseError
|
91
|
-
@logger.error("failed to parse json from a post to #{url} ... response headers and body follows...")
|
92
|
-
@logger.error(http.response_header.inspect)
|
93
|
-
@logger.error(http.response)
|
94
|
-
return nil, nil
|
95
|
-
end
|
96
|
-
status = http.response_header.status
|
97
|
-
|
98
|
-
@logger.debug("pagerduty_acknowledged?: decoded response as: #{response.inspect}")
|
99
|
-
if response.nil?
|
100
|
-
@logger.error('no valid response received from pagerduty!')
|
101
|
-
return nil, nil
|
102
|
-
end
|
103
|
-
|
104
|
-
if response['incidents'].nil?
|
105
|
-
@logger.error('no incidents found in response')
|
106
|
-
return nil, nil
|
107
|
-
end
|
108
|
-
|
109
|
-
if response['incidents'].length > 0
|
110
|
-
pg_acknowledged_by = response['incidents'].first['last_status_change_by']
|
111
|
-
return true, :pg_acknowledged_by => pg_acknowledged_by
|
112
|
-
else
|
113
|
-
return false, nil
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
def catch_pagerduty_acks
|
118
|
-
|
119
|
-
# ensure we're the only instance of the pagerduty acknowledgement check running (with a naive
|
120
|
-
# timeout of five minutes to guard against stale locks caused by crashing code) either in this
|
121
|
-
# process or in other processes
|
122
|
-
if (@pagerduty_acks_started and @pagerduty_acks_started > (Time.now.to_i - 300)) or
|
123
|
-
@redis_timer.get(@sem_pagerduty_acks_running) == 'true'
|
124
|
-
logger.debug("skipping looking for acks in pagerduty as this is already happening")
|
125
|
-
return
|
126
|
-
end
|
127
|
-
|
128
|
-
@pagerduty_acks_started = Time.now.to_i
|
129
|
-
@redis_timer.set(@sem_pagerduty_acks_running, 'true')
|
130
|
-
@redis_timer.expire(@sem_pagerduty_acks_running, 300)
|
131
|
-
|
132
|
-
logger.debug("looking for acks in pagerduty for unack'd problems")
|
133
|
-
|
134
|
-
# ok lets do it
|
135
|
-
unacknowledged_failing_checks.each {|check|
|
136
|
-
entity_check = Flapjack::Data::EntityCheck.for_event_id(check, { :redis => @redis_timer, :logger => @logger } )
|
137
|
-
pagerduty_credentials = entity_check.pagerduty_credentials(:redis => @redis_timer)
|
138
|
-
|
139
|
-
if pagerduty_credentials.length == 0
|
140
|
-
@logger.debug("Found no pagerduty creditials for #{entity_check.entity_name}:#{entity_check.check}, moving on")
|
141
|
-
next
|
142
|
-
end
|
143
|
-
|
144
|
-
# FIXME: try each set of credentials until one works (may have stale contacts turning up)
|
145
|
-
options = pagerduty_credentials.first.merge('check' => check)
|
146
|
-
|
147
|
-
pagerduty_acknowledged, result_hash = pagerduty_acknowledged?(options)
|
148
|
-
if pagerduty_acknowledged
|
149
|
-
pg_acknowledged_by = result_hash[:pg_acknowledged_by] unless result_hash.nil?
|
150
|
-
@logger.debug "#{check} is acknowledged in pagerduty, creating flapjack acknowledgement ... "
|
151
|
-
who_text = ""
|
152
|
-
if !pg_acknowledged_by.nil? && !pg_acknowledged_by['name'].nil?
|
153
|
-
who_text = " by #{pg_acknowledged_by['name']}"
|
154
|
-
end
|
155
|
-
entity_check.create_acknowledgement('summary' => "Acknowledged on PagerDuty" + who_text)
|
156
|
-
else
|
157
|
-
@logger.debug "#{check} is not acknowledged in pagerduty, moving on"
|
158
|
-
end
|
159
|
-
}
|
160
|
-
@redis_timer.del(@sem_pagerduty_acks_running)
|
161
31
|
@pagerduty_acks_started = nil
|
162
32
|
end
|
163
33
|
|
@@ -173,12 +43,12 @@ module Flapjack
|
|
173
43
|
raise "Can't connect to the pagerduty API" unless test_pagerduty_connection
|
174
44
|
|
175
45
|
# TODO: only clear this if there isn't another pagerduty gateway instance running
|
176
|
-
# or better, include
|
177
|
-
@redis.del(
|
46
|
+
# or better, include an instance ID in the semaphore key name
|
47
|
+
@redis.del(SEM_PAGERDUTY_ACKS_RUNNING)
|
178
48
|
|
179
49
|
acknowledgement_timer = EM::Synchrony.add_periodic_timer(10) do
|
180
50
|
@redis_timer ||= build_redis_connection_pool
|
181
|
-
|
51
|
+
find_pagerduty_acknowledgements_if_safe
|
182
52
|
end
|
183
53
|
|
184
54
|
queue = @config['queue']
|
@@ -190,9 +60,7 @@ module Flapjack
|
|
190
60
|
event = Yajl::Parser.parse(events[queue][1])
|
191
61
|
type = event['notification_type']
|
192
62
|
logger.debug("pagerduty notification event popped off the queue: " + event.inspect)
|
193
|
-
|
194
|
-
# do anything in particular?
|
195
|
-
else
|
63
|
+
unless 'shutdown'.eql?(type)
|
196
64
|
event_id = event['event_id']
|
197
65
|
entity, check = event_id.split(':')
|
198
66
|
state = event['state']
|
@@ -228,6 +96,138 @@ module Flapjack
|
|
228
96
|
@redis_timer.empty! if @redis_timer
|
229
97
|
end
|
230
98
|
|
99
|
+
# considering this as part of the public API -- exposes it for testing.
|
100
|
+
def find_pagerduty_acknowledgements_if_safe
|
101
|
+
|
102
|
+
# ensure we're the only instance of the pagerduty acknowledgement check running (with a naive
|
103
|
+
# timeout of five minutes to guard against stale locks caused by crashing code) either in this
|
104
|
+
# process or in other processes
|
105
|
+
if (@pagerduty_acks_started and @pagerduty_acks_started > (Time.now.to_i - 300)) or
|
106
|
+
@redis_timer.get(SEM_PAGERDUTY_ACKS_RUNNING) == 'true'
|
107
|
+
logger.debug("skipping looking for acks in pagerduty as this is already happening")
|
108
|
+
return
|
109
|
+
end
|
110
|
+
|
111
|
+
@pagerduty_acks_started = Time.now.to_i
|
112
|
+
@redis_timer.set(SEM_PAGERDUTY_ACKS_RUNNING, 'true')
|
113
|
+
@redis_timer.expire(SEM_PAGERDUTY_ACKS_RUNNING, 300)
|
114
|
+
|
115
|
+
find_pagerduty_acknowledgements
|
116
|
+
|
117
|
+
@redis_timer.del(SEM_PAGERDUTY_ACKS_RUNNING)
|
118
|
+
@pagerduty_acks_started = nil
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
def test_pagerduty_connection
|
124
|
+
noop = { "service_key" => "11111111111111111111111111111111",
|
125
|
+
"incident_key" => "Flapjack is running a NOOP",
|
126
|
+
"event_type" => "nop",
|
127
|
+
"description" => "I love APIs with noops." }
|
128
|
+
code, results = send_pagerduty_event(noop)
|
129
|
+
return true if code == 200 && results['status'] =~ /success/i
|
130
|
+
logger.error "Error: test_pagerduty_connection: API returned #{code.to_s} #{results.inspect}"
|
131
|
+
false
|
132
|
+
end
|
133
|
+
|
134
|
+
def send_pagerduty_event(event)
|
135
|
+
options = { :body => Yajl::Encoder.encode(event) }
|
136
|
+
http = EM::HttpRequest.new(PAGERDUTY_EVENTS_API_URL).post(options)
|
137
|
+
response = Yajl::Parser.parse(http.response)
|
138
|
+
status = http.response_header.status
|
139
|
+
logger.debug "send_pagerduty_event got a return code of #{status.to_s} - #{response.inspect}"
|
140
|
+
[status, response]
|
141
|
+
end
|
142
|
+
|
143
|
+
def find_pagerduty_acknowledgements
|
144
|
+
|
145
|
+
logger.debug("looking for acks in pagerduty for unack'd problems")
|
146
|
+
|
147
|
+
unacknowledged_failing_checks = Flapjack::Data::Global.unacknowledged_failing_checks(:redis => @redis_timer)
|
148
|
+
|
149
|
+
@logger.debug "found unacknowledged failing checks as follows: " + unacknowledged_failing_checks.join(', ')
|
150
|
+
|
151
|
+
unacknowledged_failing_checks.each do |entity_check|
|
152
|
+
pagerduty_credentials = entity_check.pagerduty_credentials(:redis => @redis_timer)
|
153
|
+
check = entity_check.check
|
154
|
+
|
155
|
+
if pagerduty_credentials.empty?
|
156
|
+
@logger.debug("No pagerduty credentials found for #{entity_check.entity_name}:#{check}, skipping")
|
157
|
+
next
|
158
|
+
end
|
159
|
+
|
160
|
+
# FIXME: try each set of credentials until one works (may have stale contacts turning up)
|
161
|
+
options = pagerduty_credentials.first.merge('check' => check)
|
162
|
+
|
163
|
+
acknowledged = pagerduty_acknowledged?(options)
|
164
|
+
if acknowledged.nil?
|
165
|
+
@logger.debug "#{check} is not acknowledged in pagerduty, skipping"
|
166
|
+
next
|
167
|
+
end
|
168
|
+
|
169
|
+
pg_acknowledged_by = acknowledged[:pg_acknowledged_by]
|
170
|
+
@logger.debug "#{check} is acknowledged in pagerduty, creating flapjack acknowledgement... "
|
171
|
+
who_text = ""
|
172
|
+
if !pg_acknowledged_by.nil? && !pg_acknowledged_by['name'].nil?
|
173
|
+
who_text = " by #{pg_acknowledged_by['name']}"
|
174
|
+
end
|
175
|
+
entity_check.create_acknowledgement('summary' => "Acknowledged on PagerDuty" + who_text)
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
|
180
|
+
def pagerduty_acknowledged?(opts)
|
181
|
+
subdomain = opts['subdomain']
|
182
|
+
username = opts['username']
|
183
|
+
password = opts['password']
|
184
|
+
check = opts['check']
|
185
|
+
|
186
|
+
t = Time.now.utc
|
187
|
+
|
188
|
+
url = 'https://' + subdomain + '.pagerduty.com/api/v1/incidents'
|
189
|
+
query = { 'fields' => 'incident_number,status,last_status_change_by',
|
190
|
+
'since' => (t - (60*60*24*7)).iso8601, # the last week
|
191
|
+
'until' => (t + (60*60*24)).iso8601, # 1 day in the future
|
192
|
+
'incident_key' => check,
|
193
|
+
'status' => 'acknowledged' }
|
194
|
+
|
195
|
+
options = { :head => { 'authorization' => [username, password] },
|
196
|
+
:query => query }
|
197
|
+
|
198
|
+
http = EM::HttpRequest.new(url).get(options)
|
199
|
+
# DEBUG flapjack-pagerduty: pagerduty_acknowledged?: decoded response as:
|
200
|
+
# {"incidents"=>[{"incident_number"=>40, "status"=>"acknowledged",
|
201
|
+
# "last_status_change_by"=>{"id"=>"PO1NWPS", "name"=>"Jesse Reynolds",
|
202
|
+
# "email"=>"jesse@bulletproof.net",
|
203
|
+
# "html_url"=>"http://bltprf.pagerduty.com/users/PO1NWPS"}}], "limit"=>100, "offset"=>0,
|
204
|
+
# "total"=>1}
|
205
|
+
begin
|
206
|
+
response = Yajl::Parser.parse(http.response)
|
207
|
+
rescue Yajl::ParseError
|
208
|
+
@logger.error("failed to parse json from a post to #{url} ... response headers and body follows...")
|
209
|
+
@logger.error(http.response_header.inspect)
|
210
|
+
@logger.error(http.response)
|
211
|
+
return nil
|
212
|
+
end
|
213
|
+
status = http.response_header.status
|
214
|
+
|
215
|
+
@logger.debug("pagerduty_acknowledged?: decoded response as: #{response.inspect}")
|
216
|
+
if response.nil?
|
217
|
+
@logger.error('no valid response received from pagerduty!')
|
218
|
+
return nil
|
219
|
+
end
|
220
|
+
|
221
|
+
if response['incidents'].nil?
|
222
|
+
@logger.error('no incidents found in response')
|
223
|
+
return nil
|
224
|
+
end
|
225
|
+
|
226
|
+
return nil if response['incidents'].empty?
|
227
|
+
|
228
|
+
{:pg_acknowledged_by => response['incidents'].first['last_status_change_by']}
|
229
|
+
end
|
230
|
+
|
231
231
|
end
|
232
232
|
end
|
233
233
|
|
data/lib/flapjack/redis_pool.rb
CHANGED
data/lib/flapjack/version.rb
CHANGED
@@ -105,7 +105,7 @@
|
|
105
105
|
%input{:type => 'submit', :value => 'End Now', :class => 'button'}
|
106
106
|
- else
|
107
107
|
%p No maintenance is scheduled
|
108
|
-
%h4 Add Scheduled
|
108
|
+
%h4 Add Scheduled Maintenance
|
109
109
|
%form{:action => "/scheduled_maintenances/#{@entity}/#{@check}", :method => "post"}
|
110
110
|
%fieldset
|
111
111
|
%table
|
@@ -3,14 +3,171 @@ require 'flapjack/coordinator'
|
|
3
3
|
|
4
4
|
describe Flapjack::Coordinator do
|
5
5
|
|
6
|
-
|
6
|
+
let(:fiber) { mock('Fiber') }
|
7
7
|
|
8
|
-
|
8
|
+
let(:config) {
|
9
|
+
{'redis' => {},
|
10
|
+
'executive' => {'enabled' => 'yes'},
|
11
|
+
'email_notifier' => {'enabled' => 'yes'},
|
12
|
+
'web' => {'enabled' => 'yes'}
|
13
|
+
}
|
14
|
+
}
|
9
15
|
|
10
|
-
|
16
|
+
before(:each) {
|
17
|
+
# temporary workaround for failing test due to preserved state;
|
18
|
+
# won't be needed soon as this code has been fixed in a branch
|
19
|
+
Flapjack::API.class_variable_set('@@redis', nil)
|
20
|
+
Flapjack::Web.class_variable_set('@@redis', nil)
|
21
|
+
}
|
11
22
|
|
12
|
-
|
23
|
+
# leaving actual testing of daemonisation to that class's tests
|
24
|
+
it "daemonizes properly" do
|
25
|
+
fc = Flapjack::Coordinator.new(config)
|
26
|
+
fc.should_receive(:daemonize)
|
27
|
+
fc.should_not_receive(:build_pikelet)
|
28
|
+
fc.should_not_receive(:build_resque_pikelet)
|
29
|
+
fc.should_not_receive(:build_thin_pikelet)
|
30
|
+
fc.start(:daemonize => true, :signals => false)
|
31
|
+
end
|
13
32
|
|
14
|
-
it "
|
33
|
+
it "runs undaemonized" do
|
34
|
+
EM.should_receive(:synchrony).and_yield
|
35
|
+
|
36
|
+
fc = Flapjack::Coordinator.new(config)
|
37
|
+
fc.should_receive(:build_pikelet)
|
38
|
+
fc.should_receive(:build_resque_pikelet)
|
39
|
+
fc.should_receive(:build_thin_pikelet)
|
40
|
+
fc.start(:daemonize => false, :signals => false)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "starts after daemonizing" do
|
44
|
+
EM.should_receive(:synchrony).and_yield
|
45
|
+
|
46
|
+
fc = Flapjack::Coordinator.new(config)
|
47
|
+
fc.should_receive(:build_pikelet)
|
48
|
+
fc.should_receive(:build_resque_pikelet)
|
49
|
+
fc.should_receive(:build_thin_pikelet)
|
50
|
+
fc.after_daemonize
|
51
|
+
end
|
52
|
+
|
53
|
+
it "traps system signals and shuts down"
|
54
|
+
|
55
|
+
# TODO whem merged with other changes, this will check pik[:class] instead,
|
56
|
+
# having to create instances of the pikelet classes is messy
|
57
|
+
it "stops its services when closing" do
|
58
|
+
fiber_exec = mock('fiber_exec')
|
59
|
+
fiber_rsq = mock('fiber_rsq')
|
60
|
+
|
61
|
+
exec = Flapjack::Executive.new
|
62
|
+
exec.should_receive(:add_shutdown_event)
|
63
|
+
email = EM::Resque::Worker.new('example')
|
64
|
+
email.should_receive(:shutdown)
|
65
|
+
web = Thin::Server.new('0.0.0.0', 3000, Flapjack::Web, :signals => false)
|
66
|
+
web.should_receive(:stop!)
|
67
|
+
|
68
|
+
redis = mock('redis')
|
69
|
+
redis.should_receive(:quit)
|
70
|
+
Redis.should_receive(:new).and_return(redis)
|
71
|
+
|
72
|
+
fiber.should_receive(:resume)
|
73
|
+
fiber_stop = mock('fiber_stop')
|
74
|
+
fiber_stop.should_receive(:resume)
|
75
|
+
Fiber.should_receive(:new).twice.and_yield.and_return(fiber, fiber_stop)
|
76
|
+
|
77
|
+
fiber_exec.should_receive(:alive?).and_return(true, false)
|
78
|
+
fiber_rsq.should_receive(:alive?).and_return(true, false)
|
79
|
+
|
80
|
+
EM.should_receive(:stop)
|
81
|
+
|
82
|
+
pikelets = [{:fiber => fiber_exec, :instance => exec},
|
83
|
+
{:fiber => fiber_rsq, :instance => email},
|
84
|
+
{:instance => web}]
|
85
|
+
|
86
|
+
fc = Flapjack::Coordinator.new
|
87
|
+
fc.instance_variable_set('@redis_options', {})
|
88
|
+
fc.instance_variable_set('@pikelets', pikelets)
|
89
|
+
fc.stop
|
90
|
+
end
|
91
|
+
|
92
|
+
it "creates an executive pikelet" do
|
93
|
+
exec = mock('executive')
|
94
|
+
exec.should_receive(:bootstrap)
|
95
|
+
Flapjack::Executive.should_receive(:new).and_return(exec)
|
96
|
+
exec.should_receive(:main)
|
97
|
+
|
98
|
+
fiber.should_receive(:resume)
|
99
|
+
Fiber.should_receive(:new).and_yield.and_return(fiber)
|
100
|
+
|
101
|
+
fc = Flapjack::Coordinator.new
|
102
|
+
fc.send(:build_pikelet, 'executive', {})
|
103
|
+
pikelets = fc.instance_variable_get('@pikelets')
|
104
|
+
pikelets.should_not be_nil
|
105
|
+
pikelets.should be_an(Array)
|
106
|
+
pikelets.should have(1).pikelet
|
107
|
+
pikelets.first.should == {:fiber => fiber, :type => 'executive', :instance => exec}
|
108
|
+
end
|
109
|
+
|
110
|
+
it "handles an exception raised by a jabber pikelet" do
|
111
|
+
jabber = mock('jabber')
|
112
|
+
jabber.should_receive(:bootstrap)
|
113
|
+
Flapjack::Jabber.should_receive(:new).and_return(jabber)
|
114
|
+
jabber.should_receive(:main).and_raise(RuntimeError)
|
115
|
+
|
116
|
+
fiber.should_receive(:resume)
|
117
|
+
Fiber.should_receive(:new).and_yield.and_return(fiber)
|
118
|
+
|
119
|
+
fc = Flapjack::Coordinator.new
|
120
|
+
fc.should_receive(:stop)
|
121
|
+
fc.send(:build_pikelet, 'jabber_gateway', {})
|
122
|
+
pikelets = fc.instance_variable_get('@pikelets')
|
123
|
+
pikelets.should_not be_nil
|
124
|
+
pikelets.should be_an(Array)
|
125
|
+
pikelets.should have(1).pikelet
|
126
|
+
pikelets.first.should == {:fiber => fiber, :type => 'jabber_gateway', :instance => jabber}
|
127
|
+
end
|
128
|
+
|
129
|
+
it "creates a resque worker pikelet" do
|
130
|
+
redis = mock('redis')
|
131
|
+
Flapjack::RedisPool.should_receive(:new).and_return(redis)
|
132
|
+
Resque.should_receive(:redis=).with(redis)
|
133
|
+
|
134
|
+
worker = mock('worker')
|
135
|
+
EM::Resque::Worker.should_receive(:new).and_return(worker)
|
136
|
+
worker.should_receive(:work)
|
137
|
+
|
138
|
+
fiber.should_receive(:resume)
|
139
|
+
Fiber.should_receive(:new).and_yield.and_return(fiber)
|
140
|
+
|
141
|
+
fc = Flapjack::Coordinator.new
|
142
|
+
fc.send(:build_resque_pikelet, 'email_notifier', {})
|
143
|
+
pikelets = fc.instance_variable_get('@pikelets')
|
144
|
+
pikelets.should_not be_nil
|
145
|
+
pikelets.should be_an(Array)
|
146
|
+
pikelets.should have(1).pikelet
|
147
|
+
pikelets.first.should == {:fiber => fiber, :type => 'email_notifier', :instance => worker}
|
148
|
+
end
|
149
|
+
|
150
|
+
it "handles an exception raised by a resque worker pikelet"
|
151
|
+
|
152
|
+
it "creates a thin server pikelet" do
|
153
|
+
redis = mock('redis')
|
154
|
+
Flapjack::RedisPool.should_receive(:new).and_return(redis)
|
155
|
+
|
156
|
+
server = mock('server')
|
157
|
+
server.should_receive(:start)
|
158
|
+
Thin::Server.should_receive(:new).
|
159
|
+
with(/^(?:\d{1,3}\.){3}\d{1,3}$/, an_instance_of(Fixnum), Flapjack::Web, :signals => false).
|
160
|
+
and_return(server)
|
161
|
+
|
162
|
+
fc = Flapjack::Coordinator.new
|
163
|
+
fc.send(:build_thin_pikelet, 'web', {})
|
164
|
+
pikelets = fc.instance_variable_get('@pikelets')
|
165
|
+
pikelets.should_not be_nil
|
166
|
+
pikelets.should be_an(Array)
|
167
|
+
pikelets.should have(1).pikelet
|
168
|
+
pikelets.first.should == {:type => 'web', :instance => server}
|
169
|
+
end
|
170
|
+
|
171
|
+
# NB: exceptions are handled directly by the Thin pikelets
|
15
172
|
|
16
173
|
end
|