flapjack 0.6.35 → 0.6.36
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.
- 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}
|