flapjack 0.6.35 → 0.6.36
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -1
- data/lib/flapjack/api.rb +86 -4
- data/lib/flapjack/data/contact.rb +18 -3
- data/lib/flapjack/data/entity_check.rb +35 -4
- data/lib/flapjack/executive.rb +1 -1
- data/lib/flapjack/filters/acknowledgement.rb +2 -1
- data/lib/flapjack/version.rb +1 -1
- data/lib/flapjack/web.rb +39 -13
- data/lib/flapjack/web/views/check.haml +17 -11
- data/spec/lib/flapjack/api_spec.rb +99 -0
- data/spec/lib/flapjack/data/contact_spec.rb +15 -0
- data/spec/lib/flapjack/data/entity_check_spec.rb +5 -1
- data/spec/lib/flapjack/web_spec.rb +23 -3
- metadata +4 -3
- data/lib/flapjack/web/views/acknowledge.haml +0 -55
data/Gemfile
CHANGED
@@ -6,10 +6,11 @@ group :test do
|
|
6
6
|
gem 'rspec'
|
7
7
|
gem 'cucumber'
|
8
8
|
gem 'delorean'
|
9
|
-
gem 'rack-test'
|
9
|
+
gem 'rack-test', :git => "git://github.com/brynary/rack-test.git", :ref => "8153c07"
|
10
10
|
gem 'resque_spec'
|
11
11
|
gem 'webmock'
|
12
12
|
gem 'guard'
|
13
|
+
gem 'rb-fsevent', '~> 0.9.1'
|
13
14
|
gem 'guard-rspec'
|
14
15
|
gem 'guard-cucumber'
|
15
16
|
gem 'fuubar'
|
data/lib/flapjack/api.rb
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
# A HTTP-based API server, which provides queries to determine the status of
|
4
4
|
# entities and the checks that are reported against them.
|
5
5
|
#
|
6
|
-
# There's a matching flapjack-diner gem
|
7
|
-
#
|
6
|
+
# There's a matching flapjack-diner gem at https://github.com/flpjck/flapjack-diner
|
7
|
+
# which consumes data from this API.
|
8
8
|
|
9
9
|
require 'time'
|
10
10
|
|
@@ -15,9 +15,34 @@ require 'flapjack/pikelet'
|
|
15
15
|
|
16
16
|
require 'flapjack/api/entity_presenter'
|
17
17
|
|
18
|
+
require 'flapjack/data/contact'
|
18
19
|
require 'flapjack/data/entity'
|
19
20
|
require 'flapjack/data/entity_check'
|
20
21
|
|
22
|
+
# from https://github.com/sinatra/sinatra/issues/501
|
23
|
+
# TODO move to its own file
|
24
|
+
module Rack
|
25
|
+
class JsonParamsParser < Struct.new(:app)
|
26
|
+
def call(env)
|
27
|
+
if env['rack.input'] and not input_parsed?(env) and type_match?(env)
|
28
|
+
env['rack.request.form_input'] = env['rack.input']
|
29
|
+
data = env['rack.input'].read
|
30
|
+
env['rack.request.form_hash'] = data.empty?? {} : JSON.parse(data)
|
31
|
+
end
|
32
|
+
app.call(env)
|
33
|
+
end
|
34
|
+
|
35
|
+
def input_parsed? env
|
36
|
+
env['rack.request.form_input'].eql? env['rack.input']
|
37
|
+
end
|
38
|
+
|
39
|
+
def type_match? env
|
40
|
+
type = env['CONTENT_TYPE'] and
|
41
|
+
type.split(/\s*[;,]\s*/, 2).first.downcase == 'application/json'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
21
46
|
module Flapjack
|
22
47
|
|
23
48
|
class API < Sinatra::Base
|
@@ -27,14 +52,18 @@ module Flapjack
|
|
27
52
|
rescue_exception = Proc.new { |env, exception|
|
28
53
|
logger.error exception.message
|
29
54
|
logger.error exception.backtrace.join("\n")
|
30
|
-
[503, {}, {:
|
55
|
+
[503, {}, {:errors => [exception.message]}.to_json]
|
31
56
|
}
|
32
57
|
|
33
58
|
use Rack::FiberPool, :size => 25, :rescue_exception => rescue_exception
|
34
59
|
end
|
35
60
|
use Rack::MethodOverride
|
61
|
+
use Rack::JsonParamsParser
|
62
|
+
|
36
63
|
extend Flapjack::Pikelet
|
37
64
|
|
65
|
+
set :show_exceptions, 'development'.eql?(FLAPJACK_ENV)
|
66
|
+
|
38
67
|
before do
|
39
68
|
# will only initialise the first time it's run
|
40
69
|
Flapjack::API.bootstrap
|
@@ -226,8 +255,61 @@ module Flapjack
|
|
226
255
|
status 204
|
227
256
|
end
|
228
257
|
|
258
|
+
post '/entities' do
|
259
|
+
pass unless 'application/json'.eql?(request.content_type)
|
260
|
+
content_type :json
|
261
|
+
|
262
|
+
errors = []
|
263
|
+
ret = nil
|
264
|
+
|
265
|
+
entities = params[:entities]
|
266
|
+
if entities && entities.is_a?(Enumerable) && entities.any? {|e| !e['id'].nil?}
|
267
|
+
entities.each do |entity|
|
268
|
+
unless entity['id']
|
269
|
+
errors << "Entity not imported as it has no id: #{entity.inspect}"
|
270
|
+
next
|
271
|
+
end
|
272
|
+
Flapjack::Data::Entity.add(entity, :redis => @@redis)
|
273
|
+
end
|
274
|
+
ret = 200
|
275
|
+
else
|
276
|
+
ret = 403
|
277
|
+
errors << "No valid entities were submitted"
|
278
|
+
end
|
279
|
+
errors.empty? ? ret : [ret, {}, {:errors => [errors]}.to_json]
|
280
|
+
end
|
281
|
+
|
282
|
+
post '/contacts' do
|
283
|
+
begin
|
284
|
+
pass unless 'application/json'.eql?(request.content_type)
|
285
|
+
content_type :json
|
286
|
+
|
287
|
+
errors = []
|
288
|
+
ret = nil
|
289
|
+
|
290
|
+
contacts = params[:contacts]
|
291
|
+
if contacts && contacts.is_a?(Enumerable) && contacts.any? {|c| !c['id'].nil?}
|
292
|
+
Flapjack::Data::Contact.delete_all
|
293
|
+
contacts.each do |contact|
|
294
|
+
unless contact['id']
|
295
|
+
logger.warn "Contact not imported as it has no id: #{contact.inspect}"
|
296
|
+
next
|
297
|
+
end
|
298
|
+
Flapjack::Data::Contact.add(contact, :redis => @@redis)
|
299
|
+
end
|
300
|
+
ret = 200
|
301
|
+
else
|
302
|
+
ret = 403
|
303
|
+
errors << "No valid contacts were submitted"
|
304
|
+
end
|
305
|
+
errors.empty? ? ret : [ret, {}, {:errors => [errors]}.to_json]
|
306
|
+
rescue Exception => e
|
307
|
+
puts e.message
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
229
311
|
not_found do
|
230
|
-
[404, {}, {:
|
312
|
+
[404, {}, {:errors => ["Not found"]}.to_json]
|
231
313
|
end
|
232
314
|
|
233
315
|
private
|
@@ -25,6 +25,21 @@ module Flapjack
|
|
25
25
|
union
|
26
26
|
end
|
27
27
|
|
28
|
+
def self.delete_all(options = {})
|
29
|
+
raise "Redis connection not set" unless redis = options[:redis]
|
30
|
+
|
31
|
+
contacts = redis.keys('contact:*')
|
32
|
+
|
33
|
+
contacts.each do |c|
|
34
|
+
c =~ /^contact:(\d+)$/
|
35
|
+
id = $1
|
36
|
+
|
37
|
+
redis.del("contact:#{id}")
|
38
|
+
redis.del("contact_media:#{id}")
|
39
|
+
redis.del("contact_pagerduty:#{id}")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
28
43
|
# NB: should probably be called in the context of a Redis multi block; not doing so
|
29
44
|
# here as calling classes may well be adding/updating multiple records in the one
|
30
45
|
# operation
|
@@ -34,9 +49,9 @@ module Flapjack
|
|
34
49
|
redis.del("contact:#{contact['id']}")
|
35
50
|
redis.del("contact_media:#{contact['id']}")
|
36
51
|
redis.del("contact_pagerduty:#{contact['id']}")
|
37
|
-
|
38
|
-
|
39
|
-
|
52
|
+
['first_name', 'last_name', 'email'].each do |field|
|
53
|
+
redis.hset("contact:#{contact['id']}", field, contact[field])
|
54
|
+
end
|
40
55
|
contact['media'].each_pair {|medium, address|
|
41
56
|
case medium
|
42
57
|
when 'pagerduty'
|
@@ -60,6 +60,17 @@ module Flapjack
|
|
60
60
|
@redis.exists("#{@key}:scheduled_maintenance")
|
61
61
|
end
|
62
62
|
|
63
|
+
# return data about current maintenance (scheduled or unscheduled, as specified)
|
64
|
+
def current_maintenance(opts)
|
65
|
+
sched = opts[:scheduled] ? 'scheduled' : 'unscheduled'
|
66
|
+
ts = @redis.get("#{@key}:#{sched}_maintenance")
|
67
|
+
return unless ts
|
68
|
+
{:start_time => ts.to_i,
|
69
|
+
:duration => @redis.zscore("#{@key}:#{sched}_maintenances", ts),
|
70
|
+
:summary => @redis.get("#{@key}:#{ts}:#{sched}_maintenance:summary"),
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
63
74
|
# creates, or modifies, an event object and adds it to the events list in redis
|
64
75
|
# 'type' => 'service',
|
65
76
|
# 'state' => state,
|
@@ -136,7 +147,28 @@ module Flapjack
|
|
136
147
|
@redis.zadd("#{@key}:sorted_scheduled_maintenance_timestamps", start_time, start_time)
|
137
148
|
|
138
149
|
# scheduled maintenance periods have changed, revalidate
|
139
|
-
|
150
|
+
update_current_scheduled_maintenance(:revalidate => true)
|
151
|
+
end
|
152
|
+
|
153
|
+
# change the end time of a scheduled maintenance (including when one is current)
|
154
|
+
def update_scheduled_maintenance(start_time, patches = {})
|
155
|
+
|
156
|
+
# check if there is such a scheduled maintenance period
|
157
|
+
old_duration = @redis.zscore("#{@key}:scheduled_maintenances", start_time)
|
158
|
+
raise ArgumentError, 'no such scheduled maintenance period can be found' unless old_duration
|
159
|
+
raise ArgumentError, 'no handled patches have been supplied' unless patches[:end_time]
|
160
|
+
|
161
|
+
if patches[:end_time]
|
162
|
+
end_time = patches[:end_time]
|
163
|
+
raise ArgumentError unless end_time > start_time
|
164
|
+
old_end_time = start_time + old_duration
|
165
|
+
duration = end_time - start_time
|
166
|
+
@redis.zadd("#{@key}:scheduled_maintenances", duration, start_time)
|
167
|
+
end
|
168
|
+
|
169
|
+
# scheduled maintenance periods have changed, revalidate
|
170
|
+
update_current_scheduled_maintenance(:revalidate => true)
|
171
|
+
|
140
172
|
end
|
141
173
|
|
142
174
|
# delete a scheduled maintenance
|
@@ -148,12 +180,12 @@ module Flapjack
|
|
148
180
|
@redis.zremrangebyscore("#{@key}:sorted_scheduled_maintenance_timestamps", start_time, start_time)
|
149
181
|
|
150
182
|
# scheduled maintenance periods have changed, revalidate
|
151
|
-
|
183
|
+
update_current_scheduled_maintenance(:revalidate => true)
|
152
184
|
end
|
153
185
|
|
154
186
|
# if not in scheduled maintenance, looks in scheduled maintenance list for a check to see if
|
155
187
|
# current state should be set to scheduled maintenance, and sets it as appropriate
|
156
|
-
def
|
188
|
+
def update_current_scheduled_maintenance(opts = {})
|
157
189
|
if opts[:revalidate]
|
158
190
|
@redis.del("#{@key}:scheduled_maintenance")
|
159
191
|
else
|
@@ -252,7 +284,6 @@ module Flapjack
|
|
252
284
|
ln = {:problem => last_problem_notification,
|
253
285
|
:recovery => last_recovery_notification,
|
254
286
|
:acknowledgement => last_acknowledgement_notification }
|
255
|
-
puts "***** last_notifications_of_each_type for #{@key.inspect}: #{ln.inspect}"
|
256
287
|
ln
|
257
288
|
end
|
258
289
|
|
data/lib/flapjack/executive.rb
CHANGED
@@ -161,7 +161,7 @@ module Flapjack
|
|
161
161
|
result[:skip_filters] = true
|
162
162
|
end
|
163
163
|
|
164
|
-
entity_check.
|
164
|
+
entity_check.update_current_scheduled_maintenance
|
165
165
|
|
166
166
|
# Action events represent human or automated interaction with Flapjack
|
167
167
|
when 'action'
|
@@ -21,7 +21,8 @@ module Flapjack
|
|
21
21
|
@log.error "Filter: Acknowledgement: unknown entity for event '#{event.id}'"
|
22
22
|
else
|
23
23
|
ec.create_unscheduled_maintenance(:start_time => timestamp,
|
24
|
-
:duration => (event.duration || (4 * 60 * 60))
|
24
|
+
:duration => (event.duration || (4 * 60 * 60)),
|
25
|
+
:summary => event.summary)
|
25
26
|
message = "unscheduled maintenance created for #{event.id}"
|
26
27
|
end
|
27
28
|
else
|
data/lib/flapjack/version.rb
CHANGED
data/lib/flapjack/web.rb
CHANGED
@@ -62,9 +62,9 @@ module Flapjack
|
|
62
62
|
end
|
63
63
|
|
64
64
|
get '/check' do
|
65
|
-
begin
|
65
|
+
#begin
|
66
66
|
@entity = params[:entity]
|
67
|
-
@check
|
67
|
+
@check = params[:check]
|
68
68
|
|
69
69
|
entity_check = get_entity_check(@entity, @check)
|
70
70
|
return 404 if entity_check.nil?
|
@@ -76,17 +76,18 @@ module Flapjack
|
|
76
76
|
@check_last_change = last_change
|
77
77
|
@check_summary = entity_check.summary
|
78
78
|
@last_notifications = entity_check.last_notifications_of_each_type
|
79
|
-
@in_scheduled_maintenance = entity_check.in_scheduled_maintenance?
|
80
|
-
@in_unscheduled_maintenance = entity_check.in_unscheduled_maintenance?
|
81
79
|
@scheduled_maintenances = entity_check.maintenances(nil, nil, :scheduled => true)
|
82
80
|
@acknowledgement_id = entity_check.failed? ?
|
83
81
|
entity_check.event_count_at(entity_check.last_change) : nil
|
84
82
|
|
83
|
+
@current_scheduled_maintenance = entity_check.current_maintenance(:scheduled => true)
|
84
|
+
@current_unscheduled_maintenance = entity_check.current_maintenance(:scheduled => false)
|
85
|
+
|
85
86
|
haml :check
|
86
|
-
rescue Exception => e
|
87
|
-
|
88
|
-
|
89
|
-
end
|
87
|
+
#rescue Exception => e
|
88
|
+
# puts e.message
|
89
|
+
# puts e.backtrace.join("\n")
|
90
|
+
#end
|
90
91
|
|
91
92
|
end
|
92
93
|
|
@@ -105,15 +106,13 @@ module Flapjack
|
|
105
106
|
ack = entity_check.create_acknowledgement('summary' => (@summary || ''),
|
106
107
|
'acknowledgement_id' => @acknowledgement_id, 'duration' => @duration)
|
107
108
|
|
108
|
-
|
109
|
-
@acknowledge_success = !!ack
|
110
|
-
[201, haml(:acknowledge)]
|
109
|
+
redirect back
|
111
110
|
end
|
112
111
|
|
113
112
|
# FIXME: there is bound to be a more idiomatic / restful way of doing this
|
114
113
|
post '/end_unscheduled_maintenance/:entity/:check' do
|
115
114
|
@entity = params[:entity]
|
116
|
-
@check
|
115
|
+
@check = params[:check]
|
117
116
|
|
118
117
|
entity_check = get_entity_check(@entity, @check)
|
119
118
|
return 404 if entity_check.nil?
|
@@ -130,7 +129,7 @@ module Flapjack
|
|
130
129
|
duration = ChronicDuration.parse(params[:duration])
|
131
130
|
summary = params[:summary]
|
132
131
|
|
133
|
-
entity_check = get_entity_check(params[:entity],
|
132
|
+
entity_check = get_entity_check(params[:entity], params[:check])
|
134
133
|
return 404 if entity_check.nil?
|
135
134
|
|
136
135
|
entity_check.create_scheduled_maintenance(:start_time => start_time,
|
@@ -139,6 +138,33 @@ module Flapjack
|
|
139
138
|
redirect back
|
140
139
|
end
|
141
140
|
|
141
|
+
# modify scheduled maintenance
|
142
|
+
patch '/scheduled_maintenances/:entity/:check' do
|
143
|
+
|
144
|
+
begin
|
145
|
+
puts "params: #{params.inspect}"
|
146
|
+
|
147
|
+
entity_check = get_entity_check(params[:entity], params[:check])
|
148
|
+
return 404 if entity_check.nil?
|
149
|
+
|
150
|
+
end_time = Chronic.parse(params[:end_time]).to_i
|
151
|
+
start_time = params[:start_time].to_i
|
152
|
+
raise ArgumentError, "start time parsed to zero" unless start_time > 0
|
153
|
+
|
154
|
+
patches = {}
|
155
|
+
patches[:end_time] = end_time if end_time && (end_time > start_time)
|
156
|
+
|
157
|
+
raise ArgumentError.new("no valid data received to patch with") if patches.empty?
|
158
|
+
|
159
|
+
entity_check.update_scheduled_maintenance(start_time, patches)
|
160
|
+
redirect back
|
161
|
+
|
162
|
+
rescue Exception => e
|
163
|
+
puts e.message
|
164
|
+
puts e.backtrace.join("\n")
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
142
168
|
# delete a scheduled maintenance
|
143
169
|
delete '/scheduled_maintenances/:entity/:check' do
|
144
170
|
entity_check = get_entity_check(params[:entity], params[:check])
|
@@ -49,7 +49,7 @@
|
|
49
49
|
%form{:action => "/acknowledgements/#{@entity}/#{@check}", :method => "post"}
|
50
50
|
%h2
|
51
51
|
State: #{@check_state ? @check_state.upcase : ''}
|
52
|
-
- if (['warning', 'critical'].include?(@check_state) and !(@
|
52
|
+
- if (['warning', 'critical'].include?(@check_state) and !(@current_unscheduled_maintenance || @current_scheduled_maintenance))
|
53
53
|
%input{:type => 'hidden', :name => 'acknowledgement_id', :value => "#{@acknowledgement_id}"}
|
54
54
|
%input{:type => 'submit', :value => 'Acknowledge', :class => 'button'}
|
55
55
|
with
|
@@ -59,14 +59,13 @@
|
|
59
59
|
%label{:for => 'duration'}
|
60
60
|
duration:
|
61
61
|
%input{:type => 'text', :name => 'duration', :value => ''}
|
62
|
-
|
63
|
-
|
64
|
-
- if @in_scheduled_maintenance
|
65
|
-
%h3 (Scheduled Maintenance)
|
66
|
-
- if @in_unscheduled_maintenance
|
62
|
+
- if @current_unscheduled_maintenance
|
63
|
+
%h3 (Acknowledged - #{@current_unscheduled_maintenance[:summary]})
|
67
64
|
%form{:action => "/end_unscheduled_maintenance/#{@entity}/#{@check}", :method => "post"}
|
68
65
|
%p
|
69
66
|
%input{:type => 'submit', :value => 'End Unscheduled Maintenance (Unacknowledge)', :class => 'button'}
|
67
|
+
- if @current_scheduled_maintenance
|
68
|
+
%h3 (Scheduled Maintenance - #{@current_scheduled_maintenance[:summary]})
|
70
69
|
%h3 Output: #{@check_summary}
|
71
70
|
%table
|
72
71
|
%tr
|
@@ -128,12 +127,19 @@
|
|
128
127
|
%td= summary
|
129
128
|
%td
|
130
129
|
- if end_time > Time.now.to_i
|
131
|
-
|
132
|
-
%
|
133
|
-
|
134
|
-
|
130
|
+
- if start_time > Time.now.to_i
|
131
|
+
%form{ :action => "/scheduled_maintenances/#{@entity}/#{@check}", :method => "post"}
|
132
|
+
%input{:type => 'hidden', :name => '_method', :value => 'delete'}
|
133
|
+
%input{:type => 'hidden', :name => 'start_time', :value => start_time}
|
134
|
+
%input{:type => 'submit', :value => 'Delete', :class => 'button'}
|
135
|
+
- else
|
136
|
+
%form{ :action => "/scheduled_maintenances/#{@entity}/#{@check}", :method => "post"}
|
137
|
+
%input{:type => 'hidden', :name => '_method', :value => 'patch'}
|
138
|
+
%input{:type => 'hidden', :name => 'start_time', :value => start_time}
|
139
|
+
%input{:type => 'hidden', :name => 'end_time', :value => 'now'}
|
140
|
+
%input{:type => 'submit', :value => 'End Now', :class => 'button'}
|
135
141
|
- else
|
136
|
-
%p No scheduled
|
142
|
+
%p No maintenance is scheduled
|
137
143
|
%h4 Add Scheduled Maintenace
|
138
144
|
%form{:action => "/scheduled_maintenances/#{@entity}/#{@check}", :method => "post"}
|
139
145
|
%fieldset
|
@@ -167,4 +167,103 @@ describe 'Flapjack::API', :sinatra => true do
|
|
167
167
|
last_response.body.should == result_json
|
168
168
|
end
|
169
169
|
|
170
|
+
it "creates entities from a submitted list" do
|
171
|
+
entities = {'entities' =>
|
172
|
+
[
|
173
|
+
{"id" => "10001",
|
174
|
+
"name" => "clientx-app-01",
|
175
|
+
"contacts" => ["0362","0363","0364"]
|
176
|
+
},
|
177
|
+
{"id" => "10002",
|
178
|
+
"name" => "clientx-app-02",
|
179
|
+
"contacts" => ["0362"]
|
180
|
+
}
|
181
|
+
]
|
182
|
+
}
|
183
|
+
Flapjack::Data::Entity.should_receive(:add).twice
|
184
|
+
|
185
|
+
post "/entities", entities.to_json, {'CONTENT_TYPE' => 'application/json'}
|
186
|
+
last_response.status.should == 200
|
187
|
+
end
|
188
|
+
|
189
|
+
it "does not create entities if the data is improperly formatted" do
|
190
|
+
Flapjack::Data::Entity.should_not_receive(:add)
|
191
|
+
|
192
|
+
post "/entities", {'entities' => ["Hello", "there"]}.to_json,
|
193
|
+
{'CONTENT_TYPE' => 'application/json'}
|
194
|
+
last_response.status.should == 403
|
195
|
+
end
|
196
|
+
|
197
|
+
it "does not create entities if they don't contain an id" do
|
198
|
+
entities = {'entities' =>
|
199
|
+
[
|
200
|
+
{"id" => "10001",
|
201
|
+
"name" => "clientx-app-01",
|
202
|
+
"contacts" => ["0362","0363","0364"]
|
203
|
+
},
|
204
|
+
{"name" => "clientx-app-02",
|
205
|
+
"contacts" => ["0362"]
|
206
|
+
}
|
207
|
+
]
|
208
|
+
}
|
209
|
+
Flapjack::Data::Entity.should_receive(:add)
|
210
|
+
|
211
|
+
post "/entities", entities.to_json, {'CONTENT_TYPE' => 'application/json'}
|
212
|
+
last_response.status.should == 200
|
213
|
+
end
|
214
|
+
|
215
|
+
it "creates contacts from a submitted list" do
|
216
|
+
contacts = {'contacts' =>
|
217
|
+
[{"id" => "0362",
|
218
|
+
"first_name" => "John",
|
219
|
+
"last_name" => "Smith",
|
220
|
+
"email" => "johns@example.dom",
|
221
|
+
"media" => {"email" => "johns@example.dom",
|
222
|
+
"jabber" => "johns@conference.localhost"}},
|
223
|
+
{"id" => "0363",
|
224
|
+
"first_name" => "Jane",
|
225
|
+
"last_name" => "Jones",
|
226
|
+
"email" => "jane@example.dom",
|
227
|
+
"media" => {"email" => "jane@example.dom"}}
|
228
|
+
]
|
229
|
+
}
|
230
|
+
|
231
|
+
Flapjack::Data::Contact.should_receive(:delete_all)
|
232
|
+
Flapjack::Data::Contact.should_receive(:add).twice
|
233
|
+
|
234
|
+
post "/contacts", contacts.to_json, {'CONTENT_TYPE' => 'application/json'}
|
235
|
+
last_response.status.should == 200
|
236
|
+
end
|
237
|
+
|
238
|
+
it "does not create contacts if the data is improperly formatted" do
|
239
|
+
Flapjack::Data::Contact.should_not_receive(:delete_all)
|
240
|
+
Flapjack::Data::Contact.should_not_receive(:add)
|
241
|
+
|
242
|
+
post "/contacts", {'contacts' => ["Hello", "again"]}.to_json,
|
243
|
+
{'CONTENT_TYPE' => 'application/json'}
|
244
|
+
last_response.status.should == 403
|
245
|
+
end
|
246
|
+
|
247
|
+
it "does not create contacts if they don't contain an id" do
|
248
|
+
contacts = {'contacts' =>
|
249
|
+
[{"id" => "0362",
|
250
|
+
"first_name" => "John",
|
251
|
+
"last_name" => "Smith",
|
252
|
+
"email" => "johns@example.dom",
|
253
|
+
"media" => {"email" => "johns@example.dom",
|
254
|
+
"jabber" => "johns@conference.localhost"}},
|
255
|
+
{"first_name" => "Jane",
|
256
|
+
"last_name" => "Jones",
|
257
|
+
"email" => "jane@example.dom",
|
258
|
+
"media" => {"email" => "jane@example.dom"}}
|
259
|
+
]
|
260
|
+
}
|
261
|
+
|
262
|
+
Flapjack::Data::Contact.should_receive(:delete_all)
|
263
|
+
Flapjack::Data::Contact.should_receive(:add)
|
264
|
+
|
265
|
+
post "/contacts", contacts.to_json, {'CONTENT_TYPE' => 'application/json'}
|
266
|
+
last_response.status.should == 200
|
267
|
+
end
|
268
|
+
|
170
269
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'flapjack/data/contact'
|
4
|
+
|
5
|
+
describe Flapjack::Data::Contact, :redis => true do
|
6
|
+
|
7
|
+
it "finds all contacts for a check on an entity"
|
8
|
+
|
9
|
+
it "deletes all contacts"
|
10
|
+
|
11
|
+
it "adds a contact"
|
12
|
+
|
13
|
+
it "returns pagerduty credentials for a contact"
|
14
|
+
|
15
|
+
end
|
@@ -152,6 +152,10 @@ describe Flapjack::Data::EntityCheck, :redis => true do
|
|
152
152
|
|
153
153
|
it "creates a scheduled maintenance period covering the current time"
|
154
154
|
|
155
|
+
it "updates a scheduled maintenance period for a future time"
|
156
|
+
|
157
|
+
it "updates a scheduled maintenance period covering the current time"
|
158
|
+
|
155
159
|
it "removes a scheduled maintenance period for a future time"
|
156
160
|
|
157
161
|
it "removes a scheduled maintenance period covering a current time"
|
@@ -395,4 +399,4 @@ describe Flapjack::Data::EntityCheck, :redis => true do
|
|
395
399
|
ec.last_recovery_notification.should == t
|
396
400
|
end
|
397
401
|
|
398
|
-
end
|
402
|
+
end
|
@@ -101,10 +101,10 @@ describe Flapjack::Web, :sinatra => true, :redis => true do
|
|
101
101
|
entity_check.should_receive(:last_change).and_return(time - (3 * 60 * 60))
|
102
102
|
entity_check.should_receive(:summary).and_return('all good')
|
103
103
|
entity_check.should_receive(:last_notifications_of_each_type).and_return(last_notifications)
|
104
|
-
entity_check.should_receive(:in_scheduled_maintenance?).and_return(false)
|
105
|
-
entity_check.should_receive(:in_unscheduled_maintenance?).and_return(false)
|
106
104
|
entity_check.should_receive(:maintenances).with(nil, nil, :scheduled => true).and_return([])
|
107
105
|
entity_check.should_receive(:failed?).and_return(false)
|
106
|
+
entity_check.should_receive(:current_maintenance).with(:scheduled => true).and_return(false)
|
107
|
+
entity_check.should_receive(:current_maintenance).with(:scheduled => false).and_return(false)
|
108
108
|
|
109
109
|
Flapjack::Data::Entity.should_receive(:find_by_name).
|
110
110
|
with(entity_name, :redis => @redis).and_return(entity)
|
@@ -142,7 +142,7 @@ describe Flapjack::Web, :sinatra => true, :redis => true do
|
|
142
142
|
with(an_instance_of(Hash))
|
143
143
|
|
144
144
|
post "/acknowledgements/#{entity_name_esc}/ping"
|
145
|
-
last_response.status.should ==
|
145
|
+
last_response.status.should == 302
|
146
146
|
end
|
147
147
|
|
148
148
|
it "creates a scheduled maintenance period for an entity check" do
|
@@ -169,6 +169,26 @@ describe Flapjack::Web, :sinatra => true, :redis => true do
|
|
169
169
|
last_response.status.should == 302
|
170
170
|
end
|
171
171
|
|
172
|
+
# FIXME: how to support the patch http method? ... also, is putting the post data into the url the
|
173
|
+
# way to go here?
|
174
|
+
it "updates a scheduled maintenance period for an entity check" do
|
175
|
+
t = Time.now.to_i
|
176
|
+
|
177
|
+
start_time = t - (24 * 60 * 60)
|
178
|
+
|
179
|
+
Flapjack::Data::Entity.should_receive(:find_by_name).
|
180
|
+
with(entity_name, :redis => @redis).and_return(entity)
|
181
|
+
|
182
|
+
Flapjack::Data::EntityCheck.should_receive(:for_entity).
|
183
|
+
with(entity, 'ping', :redis => @redis).and_return(entity_check)
|
184
|
+
|
185
|
+
entity_check.should_receive(:update_scheduled_maintenance).
|
186
|
+
with(start_time, {:end_time => t})
|
187
|
+
|
188
|
+
patch "/scheduled_maintenances/#{entity_name_esc}/ping", {"start_time" => start_time, "end_time" => 'now'}
|
189
|
+
last_response.status.should == 302
|
190
|
+
end
|
191
|
+
|
172
192
|
it "deletes a scheduled maintenance period for an entity check" do
|
173
193
|
t = Time.now.to_i
|
174
194
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flapjack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.36
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2012-09-
|
14
|
+
date: 2012-09-27 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: daemons
|
@@ -458,7 +458,6 @@ files:
|
|
458
458
|
- lib/flapjack/utility.rb
|
459
459
|
- lib/flapjack/version.rb
|
460
460
|
- lib/flapjack/web.rb
|
461
|
-
- lib/flapjack/web/views/acknowledge.haml
|
462
461
|
- lib/flapjack/web/views/check.haml
|
463
462
|
- lib/flapjack/web/views/index.haml
|
464
463
|
- lib/flapjack/web/views/self_stats.haml
|
@@ -495,6 +494,7 @@ files:
|
|
495
494
|
- spec/lib/flapjack/api/entity_presenter_spec.rb
|
496
495
|
- spec/lib/flapjack/api_spec.rb
|
497
496
|
- spec/lib/flapjack/coordinator_spec.rb
|
497
|
+
- spec/lib/flapjack/data/contact_spec.rb
|
498
498
|
- spec/lib/flapjack/data/entity_check_spec.rb
|
499
499
|
- spec/lib/flapjack/data/entity_spec.rb
|
500
500
|
- spec/lib/flapjack/data/event_spec.rb
|
@@ -567,6 +567,7 @@ test_files:
|
|
567
567
|
- spec/lib/flapjack/api/entity_presenter_spec.rb
|
568
568
|
- spec/lib/flapjack/api_spec.rb
|
569
569
|
- spec/lib/flapjack/coordinator_spec.rb
|
570
|
+
- spec/lib/flapjack/data/contact_spec.rb
|
570
571
|
- spec/lib/flapjack/data/entity_check_spec.rb
|
571
572
|
- spec/lib/flapjack/data/entity_spec.rb
|
572
573
|
- spec/lib/flapjack/data/event_spec.rb
|
@@ -1,55 +0,0 @@
|
|
1
|
-
!!! 5
|
2
|
-
%html
|
3
|
-
%head
|
4
|
-
:css
|
5
|
-
* { margin: 0; padding: 0; }
|
6
|
-
html { font-size: 62.5%; }
|
7
|
-
body { font-size: 16px; }
|
8
|
-
div#wrapper {
|
9
|
-
margin: 24px auto;
|
10
|
-
width: 1000px;
|
11
|
-
}
|
12
|
-
h1, h2, h3, h4, h5 {
|
13
|
-
font-family: Helvetica Neue, sans-serif;
|
14
|
-
margin-bottom: 12px;
|
15
|
-
}
|
16
|
-
table {
|
17
|
-
text-align: left;
|
18
|
-
width: 100%;
|
19
|
-
}
|
20
|
-
table th {
|
21
|
-
font-family: Helvetica Neue, sans-serif;
|
22
|
-
background-color: #eee;
|
23
|
-
}
|
24
|
-
table td, table th {
|
25
|
-
padding: 4px;
|
26
|
-
}
|
27
|
-
table td.critical {
|
28
|
-
background-color: #fb9a99;
|
29
|
-
}
|
30
|
-
table td.down {
|
31
|
-
background-color: #fb9a99;
|
32
|
-
}
|
33
|
-
table td.warning {
|
34
|
-
background-color: #f9bb34;
|
35
|
-
}
|
36
|
-
table td.ok {
|
37
|
-
background-color: #B2DF8A;
|
38
|
-
}
|
39
|
-
table td.up {
|
40
|
-
background-color: #B2DF8A;
|
41
|
-
}
|
42
|
-
%body
|
43
|
-
%div#wrapper
|
44
|
-
%p
|
45
|
-
%a(title='Dashboard' href='/') All Checks
|
46
|
-
|
|
47
|
-
%a(title='Dashboard' href='/failing') Failing Checks
|
48
|
-
- if @acknowledge_success
|
49
|
-
%h1
|
50
|
-
%a(href="/check?entity=#{@entity}&check=#{@check}") #{@check} on #{@entity}
|
51
|
-
has been acknowledged
|
52
|
-
- else
|
53
|
-
%h1
|
54
|
-
Failed to acknowledge
|
55
|
-
%a(href="/check?entity=#{@entity}&check=#{@check}") #{@check} on #{@entity}
|