flapjack 0.7.2 → 0.7.3
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/CHANGELOG.md +7 -0
- data/etc/flapjack_config.yaml.example +2 -0
- data/features/notification_rules.feature +4 -4
- data/features/steps/events_steps.rb +28 -15
- data/lib/flapjack/coordinator.rb +9 -1
- data/lib/flapjack/data/contact.rb +1 -0
- data/lib/flapjack/data/notification_rule.rb +197 -93
- data/lib/flapjack/executive.rb +11 -20
- data/lib/flapjack/gateways/api.rb +247 -363
- data/lib/flapjack/gateways/web.rb +28 -16
- data/lib/flapjack/gateways/web/views/_foot.haml +2 -2
- data/lib/flapjack/gateways/web/views/entity.haml +8 -2
- data/lib/flapjack/gateways/web/views/self_stats.haml +1 -1
- data/lib/flapjack/patches.rb +20 -1
- data/lib/flapjack/pikelet.rb +5 -14
- data/lib/flapjack/utility.rb +16 -0
- data/lib/flapjack/version.rb +1 -1
- data/spec/lib/flapjack/coordinator_spec.rb +29 -0
- data/spec/lib/flapjack/data/contact_spec.rb +1 -4
- data/spec/lib/flapjack/data/notification_rule_spec.rb +102 -9
- data/spec/lib/flapjack/gateways/api_spec.rb +9 -11
- data/spec/lib/flapjack/gateways/web_spec.rb +15 -19
- data/spec/lib/flapjack/pikelet_spec.rb +2 -56
- metadata +8 -2
data/lib/flapjack/executive.rb
CHANGED
@@ -282,9 +282,8 @@ module Flapjack
|
|
282
282
|
event, :type => notification_type, :max_notified_severity => max_notified_severity)
|
283
283
|
|
284
284
|
messages = notification.messages(:contacts => contacts)
|
285
|
-
messages = apply_notification_rules(messages)
|
285
|
+
messages = apply_notification_rules(messages, event.state)
|
286
286
|
enqueue_messages(messages)
|
287
|
-
|
288
287
|
end
|
289
288
|
|
290
289
|
# time restrictions match?
|
@@ -295,21 +294,20 @@ module Flapjack
|
|
295
294
|
contact = opts[:contact]
|
296
295
|
return true if rule.time_restrictions.nil? or rule.time_restrictions.empty?
|
297
296
|
|
298
|
-
|
299
|
-
usertime =
|
297
|
+
timezone = contact.timezone(:default => @default_contact_timezone)
|
298
|
+
usertime = timezone.now
|
300
299
|
|
301
300
|
match = rule.time_restrictions.any? do |tr|
|
302
|
-
# add contact's timezone to the time restriction
|
303
|
-
|
304
|
-
|
305
|
-
schedule
|
306
|
-
schedule.occurring_at?(usertime)
|
301
|
+
# add contact's timezone to the time restriction schedule
|
302
|
+
schedule = Flapjack::Data::NotificationRule.
|
303
|
+
time_restriction_to_icecube_schedule(tr, timezone)
|
304
|
+
schedule && schedule.occurring_at?(usertime)
|
307
305
|
end
|
308
306
|
!!match
|
309
307
|
end
|
310
308
|
|
311
309
|
# delete messages based on entity name(s), tags, severity, time of day
|
312
|
-
def apply_notification_rules(messages)
|
310
|
+
def apply_notification_rules(messages, severity)
|
313
311
|
# first get all rules matching entity and time
|
314
312
|
@logger.debug "apply_notification_rules: got messages with size #{messages.size}"
|
315
313
|
|
@@ -342,8 +340,8 @@ module Flapjack
|
|
342
340
|
end
|
343
341
|
if have_specific
|
344
342
|
# delete the rule for all entities
|
345
|
-
matchers.
|
346
|
-
matcher.entities.nil?
|
343
|
+
matchers.reject! do |matcher|
|
344
|
+
matcher.entities.nil? && matcher.entity_tags.nil?
|
347
345
|
end
|
348
346
|
end
|
349
347
|
end
|
@@ -352,7 +350,6 @@ module Flapjack
|
|
352
350
|
|
353
351
|
# delete media based on blackholes
|
354
352
|
tuple = tuple.find_all do |message, matchers, options|
|
355
|
-
severity = message.notification.event.state
|
356
353
|
# or use message.notification.contents['state']
|
357
354
|
matchers.none? {|matcher| matcher.blackhole?(severity) }
|
358
355
|
end
|
@@ -376,13 +373,7 @@ module Flapjack
|
|
376
373
|
end
|
377
374
|
options[:no_rules_for_contact] ||
|
378
375
|
matchers.any? {|matcher|
|
379
|
-
|
380
|
-
unless mms
|
381
|
-
answer = false
|
382
|
-
else
|
383
|
-
answer = mms.include?(message.medium)
|
384
|
-
end
|
385
|
-
answer
|
376
|
+
(matcher.media_for_severity(severity) || []).include?(message.medium)
|
386
377
|
}
|
387
378
|
end
|
388
379
|
|
@@ -27,7 +27,8 @@ module Rack
|
|
27
27
|
if env['rack.input'] and not input_parsed?(env) and type_match?(env)
|
28
28
|
env['rack.request.form_input'] = env['rack.input']
|
29
29
|
data = env['rack.input'].read
|
30
|
-
env['rack.
|
30
|
+
env['rack.input'].rewind
|
31
|
+
env['rack.request.form_hash'] = data.empty? ? {} : JSON.parse(data)
|
31
32
|
end
|
32
33
|
app.call(env)
|
33
34
|
end
|
@@ -48,6 +49,9 @@ module Flapjack
|
|
48
49
|
module Gateways
|
49
50
|
|
50
51
|
class API < Sinatra::Base
|
52
|
+
|
53
|
+
include Flapjack::Utility
|
54
|
+
|
51
55
|
set :show_exceptions, false
|
52
56
|
|
53
57
|
rescue_exception = Proc.new { |env, exception|
|
@@ -63,6 +67,9 @@ module Flapjack
|
|
63
67
|
class << self
|
64
68
|
def start
|
65
69
|
@redis = Flapjack::RedisPool.new(:config => @redis_config, :size => 1)
|
70
|
+
|
71
|
+
@logger.info "starting api - class"
|
72
|
+
|
66
73
|
if @config && @config['access_log']
|
67
74
|
access_logger = Flapjack::AsyncLogger.new(@config['access_log'])
|
68
75
|
use Flapjack::CommonLogger, access_logger
|
@@ -92,12 +99,9 @@ module Flapjack
|
|
92
99
|
|
93
100
|
get '/checks/:entity' do
|
94
101
|
content_type :json
|
95
|
-
|
96
|
-
|
97
|
-
status 404
|
98
|
-
return
|
102
|
+
find_entity(params[:entity]) do |entity|
|
103
|
+
entity.check_list.to_json
|
99
104
|
end
|
100
|
-
entity.check_list.to_json
|
101
105
|
end
|
102
106
|
|
103
107
|
get %r{/status/([a-zA-Z0-9][a-zA-Z0-9\.\-]*[a-zA-Z0-9])(?:/(.+))?} do
|
@@ -106,24 +110,17 @@ module Flapjack
|
|
106
110
|
entity_name = params[:captures][0]
|
107
111
|
check = params[:captures][1]
|
108
112
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
entity_check_status(entity, c)
|
120
|
-
}
|
121
|
-
end
|
122
|
-
if ret.nil?
|
123
|
-
status 404
|
124
|
-
return
|
113
|
+
find_entity(entity_name) do |entity|
|
114
|
+
ret = if check
|
115
|
+
entity_check_status(entity, check)
|
116
|
+
else
|
117
|
+
entity.check_list.sort.collect {|c|
|
118
|
+
entity_check_status(entity, c)
|
119
|
+
}
|
120
|
+
end
|
121
|
+
return error(404, "could not find entity check '#{entity_name}:#{check}'") if ret.nil?
|
122
|
+
ret.to_json
|
125
123
|
end
|
126
|
-
ret.to_json
|
127
124
|
end
|
128
125
|
|
129
126
|
# the first capture group in the regex checks for acceptable
|
@@ -135,24 +132,12 @@ module Flapjack
|
|
135
132
|
entity_name = params[:captures][0]
|
136
133
|
check = params[:captures][1]
|
137
134
|
|
138
|
-
entity = entity = Flapjack::Data::Entity.find_by_name(entity_name, :redis => redis)
|
139
|
-
if entity.nil?
|
140
|
-
status 404
|
141
|
-
return
|
142
|
-
end
|
143
|
-
|
144
135
|
start_time = validate_and_parsetime(params[:start_time])
|
145
136
|
end_time = validate_and_parsetime(params[:end_time])
|
146
137
|
|
147
|
-
|
148
|
-
|
149
|
-
check, :redis => redis)
|
150
|
-
Flapjack::Gateways::API::EntityCheckPresenter.new(entity_check)
|
151
|
-
else
|
152
|
-
Flapjack::Gateways::API::EntityPresenter.new(entity, :redis => redis)
|
138
|
+
find_api_presenter(entity_name, check) do |presenter|
|
139
|
+
presenter.outages(start_time, end_time).to_json
|
153
140
|
end
|
154
|
-
|
155
|
-
presenter.outages(start_time, end_time).to_json
|
156
141
|
end
|
157
142
|
|
158
143
|
get %r{/unscheduled_maintenances/([a-zA-Z0-9][a-zA-Z0-9\.\-]*[a-zA-Z0-9])(?:/(\w+))?} do
|
@@ -161,24 +146,12 @@ module Flapjack
|
|
161
146
|
entity_name = params[:captures][0]
|
162
147
|
check = params[:captures][1]
|
163
148
|
|
164
|
-
entity = Flapjack::Data::Entity.find_by_name(entity_name, :redis => redis)
|
165
|
-
if entity.nil?
|
166
|
-
status 404
|
167
|
-
return
|
168
|
-
end
|
169
|
-
|
170
149
|
start_time = validate_and_parsetime(params[:start_time])
|
171
150
|
end_time = validate_and_parsetime(params[:end_time])
|
172
151
|
|
173
|
-
|
174
|
-
|
175
|
-
check, :redis => redis)
|
176
|
-
Flapjack::Gateways::API::EntityCheckPresenter.new(entity_check)
|
177
|
-
else
|
178
|
-
Flapjack::Gateways::API::EntityPresenter.new(entity, :redis => redis)
|
152
|
+
find_api_presenter(entity_name, check) do |presenter|
|
153
|
+
presenter.unscheduled_maintenance(start_time, end_time).to_json
|
179
154
|
end
|
180
|
-
|
181
|
-
presenter.unscheduled_maintenance(start_time, end_time).to_json
|
182
155
|
end
|
183
156
|
|
184
157
|
get %r{/scheduled_maintenances/([a-zA-Z0-9][a-zA-Z0-9\.\-]*[a-zA-Z0-9])(?:/(\w+))?} do
|
@@ -187,23 +160,12 @@ module Flapjack
|
|
187
160
|
entity_name = params[:captures][0]
|
188
161
|
check = params[:captures][1]
|
189
162
|
|
190
|
-
entity = Flapjack::Data::Entity.find_by_name(entity_name, :redis => redis)
|
191
|
-
if entity.nil?
|
192
|
-
status 404
|
193
|
-
return
|
194
|
-
end
|
195
|
-
|
196
163
|
start_time = validate_and_parsetime(params[:start_time])
|
197
164
|
end_time = validate_and_parsetime(params[:end_time])
|
198
165
|
|
199
|
-
|
200
|
-
|
201
|
-
check, :redis => redis)
|
202
|
-
Flapjack::Gateways::API::EntityCheckPresenter.new(entity_check)
|
203
|
-
else
|
204
|
-
Flapjack::Gateways::API::EntityPresenter.new(entity, :redis => redis)
|
166
|
+
find_api_presenter(entity_name, check) do |presenter|
|
167
|
+
presenter.scheduled_maintenance(start_time, end_time).to_json
|
205
168
|
end
|
206
|
-
presenter.scheduled_maintenance(start_time, end_time).to_json
|
207
169
|
end
|
208
170
|
|
209
171
|
get %r{/downtime/([a-zA-Z0-9][a-zA-Z0-9\.\-]*[a-zA-Z0-9])(?:/(\w+))?} do
|
@@ -212,42 +174,27 @@ module Flapjack
|
|
212
174
|
entity_name = params[:captures][0]
|
213
175
|
check = params[:captures][1]
|
214
176
|
|
215
|
-
entity = Flapjack::Data::Entity.find_by_name(entity_name, :redis => redis)
|
216
|
-
if entity.nil?
|
217
|
-
status 404
|
218
|
-
return
|
219
|
-
end
|
220
|
-
|
221
177
|
start_time = validate_and_parsetime(params[:start_time])
|
222
178
|
end_time = validate_and_parsetime(params[:end_time])
|
223
179
|
|
224
|
-
|
225
|
-
|
226
|
-
check, :redis => redis)
|
227
|
-
Flapjack::Gateways::API::EntityCheckPresenter.new(entity_check)
|
228
|
-
else
|
229
|
-
Flapjack::Gateways::API::EntityPresenter.new(entity, :redis => redis)
|
180
|
+
find_api_presenter(entity_name, check) do |presenter|
|
181
|
+
presenter.downtime(start_time, end_time).to_json
|
230
182
|
end
|
231
|
-
|
232
|
-
presenter.downtime(start_time, end_time).to_json
|
233
183
|
end
|
234
184
|
|
235
185
|
# create a scheduled maintenance period for a service on an entity
|
236
186
|
post '/scheduled_maintenances/:entity/:check' do
|
237
187
|
content_type :json
|
238
|
-
entity = Flapjack::Data::Entity.find_by_name(params[:entity], :redis => redis)
|
239
|
-
if entity.nil?
|
240
|
-
status 404
|
241
|
-
return
|
242
|
-
end
|
243
|
-
entity_check = Flapjack::Data::EntityCheck.for_entity(entity,
|
244
|
-
params[:check], :redis => redis)
|
245
188
|
|
246
189
|
start_time = validate_and_parsetime(params[:start_time])
|
247
190
|
|
248
|
-
|
249
|
-
|
250
|
-
|
191
|
+
find_entity(params[:entity]) do |entity|
|
192
|
+
find_entity_check(entity, params[:check]) do |entity_check|
|
193
|
+
entity_check.create_scheduled_maintenance(:start_time => start_time,
|
194
|
+
:duration => params[:duration].to_i, :summary => params[:summary])
|
195
|
+
status 204
|
196
|
+
end
|
197
|
+
end
|
251
198
|
end
|
252
199
|
|
253
200
|
# create an acknowledgement for a service on an entity
|
@@ -255,36 +202,28 @@ module Flapjack
|
|
255
202
|
# the entity-check as a whole
|
256
203
|
post '/acknowledgements/:entity/:check' do
|
257
204
|
content_type :json
|
258
|
-
entity = Flapjack::Data::Entity.find_by_name(params[:entity], :redis => redis)
|
259
|
-
if entity.nil?
|
260
|
-
status 404
|
261
|
-
return
|
262
|
-
end
|
263
205
|
|
264
206
|
dur = params[:duration] ? params[:duration].to_i : nil
|
265
207
|
duration = (dur.nil? || (dur <= 0)) ? (4 * 60 * 60) : dur
|
266
208
|
|
267
|
-
|
268
|
-
params[:check]
|
269
|
-
|
270
|
-
|
271
|
-
|
209
|
+
find_entity(params[:entity]) do |entity|
|
210
|
+
find_entity_check(entity, params[:check]) do |entity_check|
|
211
|
+
entity_check.create_acknowledgement('summary' => params[:summary],
|
212
|
+
'duration' => duration)
|
213
|
+
status 204
|
214
|
+
end
|
215
|
+
end
|
272
216
|
end
|
273
217
|
|
274
218
|
post '/test_notifications/:entity/:check' do
|
275
219
|
content_type :json
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
220
|
+
find_entity(params[:entity]) do |entity|
|
221
|
+
find_entity_check(entity, params[:check]) do |entity_check|
|
222
|
+
summary = params[:summary] || "Testing notifications to all contacts interested in entity #{entity.name}"
|
223
|
+
entity_check.test_notifications('summary' => summary)
|
224
|
+
status 204
|
225
|
+
end
|
280
226
|
end
|
281
|
-
|
282
|
-
summary = params[:summary] || "Testing notifications to all contacts interested in entity #{entity.name}"
|
283
|
-
|
284
|
-
entity_check = Flapjack::Data::EntityCheck.for_entity(entity,
|
285
|
-
params[:check], :redis => redis)
|
286
|
-
entity_check.test_notifications('summary' => summary)
|
287
|
-
status 204
|
288
227
|
end
|
289
228
|
|
290
229
|
post '/entities' do
|
@@ -294,21 +233,26 @@ module Flapjack
|
|
294
233
|
errors = []
|
295
234
|
ret = nil
|
296
235
|
|
236
|
+
# FIXME should scan for invalid records before making any changes, fail early
|
237
|
+
|
297
238
|
entities = params[:entities]
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
239
|
+
unless entities
|
240
|
+
logger.debug("no entities object found in the following supplied JSON:")
|
241
|
+
logger.debug(request.body)
|
242
|
+
return error(403, "No entities object received")
|
243
|
+
end
|
244
|
+
return error(403, "The received entities object is not an Enumerable") unless entities.is_a?(Enumerable)
|
245
|
+
return error(403, "Entity with a nil id detected") unless entities.any? {|e| !e['id'].nil?}
|
246
|
+
|
247
|
+
entities.each do |entity|
|
248
|
+
unless entity['id']
|
249
|
+
errors << "Entity not imported as it has no id: #{entity.inspect}"
|
250
|
+
next
|
305
251
|
end
|
306
|
-
|
307
|
-
else
|
308
|
-
ret = 403
|
309
|
-
errors << "No valid entities were submitted"
|
252
|
+
Flapjack::Data::Entity.add(entity, :redis => redis)
|
310
253
|
end
|
311
|
-
|
254
|
+
|
255
|
+
errors.empty? ? 204 : error(403, *errors)
|
312
256
|
end
|
313
257
|
|
314
258
|
post '/contacts' do
|
@@ -349,7 +293,7 @@ module Flapjack
|
|
349
293
|
end
|
350
294
|
end
|
351
295
|
end
|
352
|
-
errors.empty? ?
|
296
|
+
errors.empty? ? 204 : error(403, *errors)
|
353
297
|
end
|
354
298
|
|
355
299
|
# Returns all the contacts
|
@@ -363,369 +307,325 @@ module Flapjack
|
|
363
307
|
# https://github.com/flpjck/flapjack/wiki/API#wiki-get_contacts_id
|
364
308
|
get '/contacts/:contact_id' do
|
365
309
|
content_type :json
|
366
|
-
|
367
|
-
|
368
|
-
logger.warn "contact not found with id #{params[:contact_id]}"
|
369
|
-
status 404
|
370
|
-
return
|
310
|
+
find_contact(params[:contact_id]) do |contact|
|
311
|
+
contact.to_json
|
371
312
|
end
|
372
|
-
contact.to_json
|
373
313
|
end
|
374
314
|
|
375
315
|
# Lists this contact's notification rules
|
376
316
|
# https://github.com/flpjck/flapjack/wiki/API#wiki-get_contacts_id_notification_rules
|
377
317
|
get '/contacts/:contact_id/notification_rules' do
|
378
318
|
content_type :json
|
379
|
-
|
380
|
-
|
381
|
-
logger.warn "contact not found with id #{params[:contact_id]}"
|
382
|
-
status 404
|
383
|
-
return
|
319
|
+
find_contact(params[:contact_id]) do |contact|
|
320
|
+
contact.notification_rules.to_json
|
384
321
|
end
|
385
|
-
contact.notification_rules.to_json
|
386
322
|
end
|
387
323
|
|
388
324
|
# Get the specified notification rule for this user
|
389
325
|
# https://github.com/flpjck/flapjack/wiki/API#wiki-get_contacts_id_notification_rules_id
|
390
|
-
get '/notification_rules/:
|
326
|
+
get '/notification_rules/:id' do
|
391
327
|
content_type :json
|
392
328
|
|
393
|
-
|
394
|
-
|
395
|
-
logger.warn("Unable to find a notification rule with id [#{params[:rule_id]}]")
|
396
|
-
status 404
|
397
|
-
return
|
329
|
+
find_rule(params[:id]) do |rule|
|
330
|
+
rule.to_json
|
398
331
|
end
|
399
|
-
rule.to_json
|
400
332
|
end
|
401
333
|
|
402
334
|
# Creates a notification rule for a contact
|
403
335
|
# https://github.com/flpjck/flapjack/wiki/API#wiki-post_contacts_id_notification_rules
|
404
336
|
post '/notification_rules' do
|
405
|
-
# # NB if parameters are correctly passed, we shouldn't mandate a request format
|
406
|
-
# pass unless 'application/json'.eql?(request.content_type)
|
407
337
|
content_type :json
|
408
|
-
|
409
|
-
contact = Flapjack::Data::Contact.find_by_id(params[:contact_id], :redis => redis)
|
410
|
-
if contact.nil?
|
411
|
-
logger.warn "contact not found with id #{params[:contact_id]}"
|
412
|
-
status 404
|
413
|
-
return
|
414
|
-
end
|
415
338
|
if params[:id]
|
416
|
-
|
417
|
-
status 403
|
418
|
-
return
|
339
|
+
return error(403, "post cannot be used for update, do a put instead")
|
419
340
|
end
|
420
341
|
|
421
|
-
|
422
|
-
|
423
|
-
:
|
424
|
-
|
425
|
-
|
342
|
+
find_contact(params[:contact_id]) do |contact|
|
343
|
+
|
344
|
+
rule_data = hashify(:entities, :entity_tags,
|
345
|
+
:warning_media, :critical_media, :time_restrictions,
|
346
|
+
:warning_blackhole, :critical_blackhole) {|k| [k, params[k]]}
|
347
|
+
|
348
|
+
unless rule = contact.add_notification_rule(rule_data)
|
349
|
+
return error(403, "invalid notification rule data")
|
350
|
+
end
|
351
|
+
rule.to_json
|
352
|
+
end
|
426
353
|
end
|
427
354
|
|
428
355
|
# Updates a notification rule
|
429
356
|
# https://github.com/flpjck/flapjack/wiki/API#wiki-put_notification_rules_id
|
430
357
|
put('/notification_rules/:id') do
|
431
|
-
# # NB if parameters are correctly passed, we shouldn't mandate a request format
|
432
|
-
# pass unless 'application/json'.eql?(request.content_type)
|
433
358
|
content_type :json
|
359
|
+
find_rule(params[:id]) do |rule|
|
360
|
+
find_contact(rule.contact_id) do |contact|
|
434
361
|
|
435
|
-
|
362
|
+
rule_data = hashify(:entities, :entity_tags,
|
363
|
+
:warning_media, :critical_media, :time_restrictions,
|
364
|
+
:warning_blackhole, :critical_blackhole) {|k| [k, params[k]]}
|
436
365
|
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
end
|
443
|
-
rule = Flapjack::Data::NotificationRule.find_by_id(params[:id], :redis => redis)
|
444
|
-
if rule.nil?
|
445
|
-
logger.warn "rule not found with id #{params[:id]}"
|
446
|
-
status 404
|
447
|
-
return
|
366
|
+
unless rule.update(rule_data)
|
367
|
+
return error(403, "invalid notification rule data")
|
368
|
+
end
|
369
|
+
rule.to_json
|
370
|
+
end
|
448
371
|
end
|
449
|
-
|
450
|
-
rule_data = hashify(:entities, :entity_tags,
|
451
|
-
:warning_media, :critical_media, :time_restrictions,
|
452
|
-
:warning_blackhole, :critical_blackhole) {|k| [k, params[k]]}
|
453
|
-
rule.update(rule_data)
|
454
|
-
rule.to_json
|
455
372
|
end
|
456
373
|
|
457
374
|
# Deletes a notification rule
|
458
375
|
# https://github.com/flpjck/flapjack/wiki/API#wiki-put_notification_rules_id
|
459
376
|
delete('/notification_rules/:id') do
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
contact = Flapjack::Data::Contact.find_by_id(rule.contact_id, :redis => redis)
|
466
|
-
if contact.nil?
|
467
|
-
logger.warn "contact not found with id #{rule.contact_id}"
|
468
|
-
status 404
|
469
|
-
return
|
377
|
+
find_rule(params[:id]) do |rule|
|
378
|
+
find_contact(rule.contact_id) do |contact|
|
379
|
+
contact.delete_notification_rule(rule)
|
380
|
+
status 204
|
381
|
+
end
|
470
382
|
end
|
471
|
-
contact.delete_notification_rule(rule)
|
472
|
-
status 204
|
473
383
|
end
|
474
384
|
|
475
385
|
# Returns the media of a contact
|
476
386
|
# https://github.com/flpjck/flapjack/wiki/API#wiki-get_contacts_id_media
|
477
387
|
get '/contacts/:contact_id/media' do
|
478
388
|
content_type :json
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
389
|
+
find_contact(params[:contact_id]) do |contact|
|
390
|
+
media = contact.media
|
391
|
+
media_intervals = contact.media_intervals
|
392
|
+
media_addr_int = hashify(*media.keys) {|k|
|
393
|
+
[k, {'address' => media[k],
|
394
|
+
'interval' => media_intervals[k] }]
|
395
|
+
}
|
396
|
+
media_addr_int.to_json
|
483
397
|
end
|
484
|
-
media = contact.media
|
485
|
-
media_intervals = contact.media_intervals
|
486
|
-
media_addr_int = hashify(*media.keys) {|k|
|
487
|
-
[k, {'address' => media[k],
|
488
|
-
'interval' => media_intervals[k] }]
|
489
|
-
}
|
490
|
-
media_addr_int.to_json
|
491
398
|
end
|
492
399
|
|
493
400
|
# Returns the specified media of a contact
|
494
401
|
# https://github.com/flpjck/flapjack/wiki/API#wiki-get_contacts_id_media_media
|
495
|
-
get('/contacts/:contact_id/media/:
|
402
|
+
get('/contacts/:contact_id/media/:id') do
|
496
403
|
content_type :json
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
return
|
404
|
+
find_contact(params[:contact_id]) do |contact|
|
405
|
+
if contact.media[params[:id]].nil?
|
406
|
+
status 404
|
407
|
+
return
|
408
|
+
end
|
409
|
+
{'address' => contact.media[params[:id]],
|
410
|
+
'interval' => contact.media_intervals[params[:id]]}.to_json
|
505
411
|
end
|
506
|
-
{ 'address' => contact.media[params[:media_id]],
|
507
|
-
'interval' => contact.media_intervals[params[:media_id]] }.to_json
|
508
412
|
end
|
509
413
|
|
510
414
|
# Creates or updates a media of a contact
|
511
415
|
# https://github.com/flpjck/flapjack/wiki/API#wiki-put_contacts_id_media_media
|
512
|
-
put('/contacts/:contact_id/media/:
|
416
|
+
put('/contacts/:contact_id/media/:id') do
|
513
417
|
content_type :json
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
418
|
+
find_contact(params[:contact_id]) do |contact|
|
419
|
+
errors = []
|
420
|
+
if params[:address].nil?
|
421
|
+
errors << "no address for '#{params[:id]}' media"
|
422
|
+
end
|
423
|
+
if params[:interval].nil?
|
424
|
+
errors << "no interval for '#{params[:id]}' media"
|
425
|
+
end
|
426
|
+
|
427
|
+
return error(403, *errors) unless errors.empty?
|
428
|
+
|
429
|
+
contact.set_address_for_media(params[:id], params[:address])
|
430
|
+
contact.set_interval_for_media(params[:id], params[:interval])
|
525
431
|
|
526
|
-
|
527
|
-
|
432
|
+
{'address' => contact.media[params[:id]],
|
433
|
+
'interval' => contact.media_intervals[params[:id]]}.to_json
|
434
|
+
end
|
528
435
|
end
|
529
436
|
|
530
437
|
# delete a media of a contact
|
531
|
-
delete('/contacts/:contact_id/media/:
|
532
|
-
|
533
|
-
|
534
|
-
status
|
535
|
-
return
|
438
|
+
delete('/contacts/:contact_id/media/:id') do
|
439
|
+
find_contact(params[:contact_id]) do |contact|
|
440
|
+
contact.remove_media(params[:id])
|
441
|
+
status 204
|
536
442
|
end
|
537
|
-
contact.remove_media(params[:media_id])
|
538
|
-
status 204
|
539
443
|
end
|
540
444
|
|
541
445
|
# Returns the timezone of a contact
|
542
446
|
# https://github.com/flpjck/flapjack/wiki/API#wiki-get_contacts_id_timezone
|
543
447
|
get('/contacts/:contact_id/timezone') do
|
544
448
|
content_type :json
|
545
|
-
|
546
|
-
|
547
|
-
status 404
|
548
|
-
return
|
449
|
+
find_contact(params[:contact_id]) do |contact|
|
450
|
+
contact.timezone.name.to_json
|
549
451
|
end
|
550
|
-
contact.timezone.name.to_json
|
551
452
|
end
|
552
453
|
|
553
454
|
# Sets the timezone of a contact
|
554
455
|
# https://github.com/flpjck/flapjack/wiki/API#wiki-put_contacts_id_timezone
|
555
456
|
put('/contacts/:contact_id/timezone') do
|
556
457
|
content_type :json
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
return
|
458
|
+
find_contact(params[:contact_id]) do |contact|
|
459
|
+
contact.timezone = params[:timezone]
|
460
|
+
contact.timezone.name.to_json
|
561
461
|
end
|
562
|
-
contact.timezone = params[:timezone]
|
563
|
-
contact.timezone.name.to_json
|
564
462
|
end
|
565
463
|
|
566
464
|
# Removes the timezone of a contact
|
567
465
|
# https://github.com/flpjck/flapjack/wiki/API#wiki-put_contacts_id_timezone
|
568
466
|
delete('/contacts/:contact_id/timezone') do
|
569
|
-
|
570
|
-
|
571
|
-
status
|
572
|
-
return
|
467
|
+
find_contact(params[:contact_id]) do |contact|
|
468
|
+
contact.timezone = nil
|
469
|
+
status 204
|
573
470
|
end
|
574
|
-
contact.timezone = nil
|
575
|
-
status 204
|
576
471
|
end
|
577
472
|
|
578
473
|
post '/contacts/:contact_id/tags' do
|
579
474
|
content_type :json
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
tags = params[:tag]
|
586
|
-
if tags.nil? || tags.empty?
|
587
|
-
status 403
|
588
|
-
return
|
475
|
+
check_tags(params[:tag]) do |tags|
|
476
|
+
find_contact(params[:contact_id]) do |contact|
|
477
|
+
contact.add_tags(*tags)
|
478
|
+
contact.tags.to_json
|
479
|
+
end
|
589
480
|
end
|
590
|
-
tags = [tags] unless tags.respond_to?(:each)
|
591
|
-
contact.add_tags(*tags)
|
592
|
-
contact.tags.to_json
|
593
481
|
end
|
594
482
|
|
595
483
|
post '/contacts/:contact_id/entity_tags' do
|
596
484
|
content_type :json
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
485
|
+
find_contact(params[:contact_id]) do |contact|
|
486
|
+
contact.entities.map {|e| e[:entity]}.each do |entity|
|
487
|
+
next unless tags = params[:entity][entity.name]
|
488
|
+
entity.add_tags(*tags)
|
489
|
+
end
|
490
|
+
contact_ent_tag = hashify(*contact.entities(:tags => true)) {|et|
|
491
|
+
[et[:entity].name, et[:tags]]
|
492
|
+
}
|
493
|
+
contact_ent_tag.to_json
|
605
494
|
end
|
606
|
-
contact_ent_tag = hashify(*contact.entities(:tags => true)) {|et|
|
607
|
-
[et[:entity].name, et[:tags]]
|
608
|
-
}
|
609
|
-
contact_ent_tag.to_json
|
610
495
|
end
|
611
496
|
|
612
497
|
delete '/contacts/:contact_id/tags' do
|
613
498
|
content_type :json
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
tags = params[:tag]
|
620
|
-
if tags.nil? || tags.empty?
|
621
|
-
status 403
|
622
|
-
return
|
499
|
+
check_tags(params[:tag]) do |tags|
|
500
|
+
find_contact(params[:contact_id]) do |contact|
|
501
|
+
contact.delete_tags(*tags)
|
502
|
+
status 204
|
503
|
+
end
|
623
504
|
end
|
624
|
-
tags = [tags] unless tags.respond_to?(:each)
|
625
|
-
contact.delete_tags(*tags)
|
626
|
-
status 204
|
627
505
|
end
|
628
506
|
|
629
507
|
delete '/contacts/:contact_id/entity_tags' do
|
630
508
|
content_type :json
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
next unless tags = params[:entity][entity.name]
|
638
|
-
entity.delete_tags(*tags)
|
509
|
+
find_contact(params[:contact_id]) do |contact|
|
510
|
+
contact.entities.map {|e| e[:entity]}.each do |entity|
|
511
|
+
next unless tags = params[:entity][entity.name]
|
512
|
+
entity.delete_tags(*tags)
|
513
|
+
end
|
514
|
+
status 204
|
639
515
|
end
|
640
|
-
status 204
|
641
516
|
end
|
642
517
|
|
643
518
|
get '/contacts/:contact_id/tags' do
|
644
519
|
content_type :json
|
645
|
-
|
646
|
-
|
647
|
-
status 404
|
648
|
-
return
|
520
|
+
find_contact(params[:contact_id]) do |contact|
|
521
|
+
contact.tags.to_json
|
649
522
|
end
|
650
|
-
contact.tags.to_json
|
651
523
|
end
|
652
524
|
|
653
525
|
get '/contacts/:contact_id/entity_tags' do
|
654
526
|
content_type :json
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
527
|
+
find_contact(params[:contact_id]) do |contact|
|
528
|
+
contact_ent_tag = hashify(*contact.entities(:tags => true)) {|et|
|
529
|
+
[et[:entity].name, et[:tags]]
|
530
|
+
}
|
531
|
+
contact_ent_tag.to_json
|
659
532
|
end
|
660
|
-
contact_ent_tag = hashify(*contact.entities(:tags => true)) {|et|
|
661
|
-
[et[:entity].name, et[:tags]]
|
662
|
-
}
|
663
|
-
contact_ent_tag.to_json
|
664
533
|
end
|
665
534
|
|
666
535
|
post '/entities/:entity/tags' do
|
667
536
|
content_type :json
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
tags = params[:tag]
|
674
|
-
if tags.nil? || tags.empty?
|
675
|
-
status 403
|
676
|
-
return
|
537
|
+
check_tags(params[:tag]) do |tags|
|
538
|
+
find_entity(params[:entity]) do |entity|
|
539
|
+
entity.add_tags(*tags)
|
540
|
+
entity.tags.to_json
|
541
|
+
end
|
677
542
|
end
|
678
|
-
tags = [tags] unless tags.respond_to?(:each)
|
679
|
-
entity.add_tags(*tags)
|
680
|
-
entity.tags.to_json
|
681
543
|
end
|
682
544
|
|
683
545
|
delete '/entities/:entity/tags' do
|
684
546
|
content_type :json
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
tags = params[:tag]
|
691
|
-
if tags.nil? || tags.empty?
|
692
|
-
status 403
|
693
|
-
return
|
547
|
+
check_tags(params[:tag]) do |tags|
|
548
|
+
find_entity(params[:entity]) do |entity|
|
549
|
+
entity.delete_tags(*tags)
|
550
|
+
status 204
|
551
|
+
end
|
694
552
|
end
|
695
|
-
tags = [tags] unless tags.respond_to?(:each)
|
696
|
-
entity.delete_tags(*tags)
|
697
|
-
status 204
|
698
553
|
end
|
699
554
|
|
700
555
|
get '/entities/:entity/tags' do
|
701
556
|
content_type :json
|
702
|
-
|
703
|
-
|
704
|
-
status 404
|
705
|
-
return
|
557
|
+
find_entity(params[:entity]) do |entity|
|
558
|
+
entity.tags.to_json
|
706
559
|
end
|
707
|
-
entity.tags.to_json
|
708
560
|
end
|
709
561
|
|
710
562
|
not_found do
|
711
|
-
|
563
|
+
error(404, "not routable")
|
712
564
|
end
|
713
565
|
|
714
566
|
private
|
715
567
|
|
568
|
+
def error(status, *msg)
|
569
|
+
msg_str = msg.join(", ")
|
570
|
+
logger.info "Error: #{msg_str}"
|
571
|
+
[status, {}, {:errors => msg}.to_json]
|
572
|
+
end
|
573
|
+
|
716
574
|
def entity_check_status(entity, check)
|
717
575
|
entity_check = Flapjack::Data::EntityCheck.for_entity(entity,
|
718
576
|
check, :redis => redis)
|
719
577
|
return if entity_check.nil?
|
720
|
-
{
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
578
|
+
{'name' => check,
|
579
|
+
'state' => entity_check.state,
|
580
|
+
'in_unscheduled_maintenance' => entity_check.in_unscheduled_maintenance?,
|
581
|
+
'in_scheduled_maintenance' => entity_check.in_scheduled_maintenance?,
|
582
|
+
'last_update' => entity_check.last_update,
|
583
|
+
'last_problem_notification' => entity_check.last_problem_notification,
|
584
|
+
'last_recovery_notification' => entity_check.last_recovery_notification,
|
585
|
+
'last_acknowledgement_notification' => entity_check.last_acknowledgement_notification}
|
586
|
+
end
|
587
|
+
|
588
|
+
# following a callback-heavy pattern -- feels like nodejs :)
|
589
|
+
def find_contact(contact_id, &block)
|
590
|
+
contact = Flapjack::Data::Contact.find_by_id(contact_id, :redis => redis)
|
591
|
+
return(yield(contact)) if contact
|
592
|
+
error(404, "could not find contact with id '#{contact_id}'")
|
593
|
+
end
|
594
|
+
|
595
|
+
def find_rule(rule_id, &block)
|
596
|
+
rule = Flapjack::Data::NotificationRule.find_by_id(rule_id, :redis => redis)
|
597
|
+
return(yield(rule)) if rule
|
598
|
+
error(404, "could not find notification rule with id '#{rule_id}'")
|
599
|
+
end
|
600
|
+
|
601
|
+
def find_entity(entity_name, &block)
|
602
|
+
entity = Flapjack::Data::Entity.find_by_name(entity_name, :redis => redis)
|
603
|
+
return(yield(entity)) if entity
|
604
|
+
error(404, "could not find entity '#{entity_name}'")
|
605
|
+
end
|
606
|
+
|
607
|
+
def find_entity_check(entity, check, &block)
|
608
|
+
entity_check = Flapjack::Data::EntityCheck.for_entity(entity,
|
609
|
+
check, :redis => redis)
|
610
|
+
return(yield(entity_check)) if entity_check
|
611
|
+
error(404, "could not find entity check '#{entity.name}:#{check}'")
|
612
|
+
end
|
613
|
+
|
614
|
+
def find_api_presenter(entity_name, check, &block)
|
615
|
+
find_entity(entity_name) do |entity|
|
616
|
+
if check
|
617
|
+
find_entity_check(entity, check) do |entity_check|
|
618
|
+
yield(Flapjack::Gateways::API::EntityCheckPresenter.new(entity_check))
|
619
|
+
end
|
620
|
+
else
|
621
|
+
yield(Flapjack::Gateways::API::EntityPresenter.new(entity, :redis => redis))
|
622
|
+
end
|
623
|
+
end
|
624
|
+
end
|
625
|
+
|
626
|
+
def check_tags(tags)
|
627
|
+
return(yield(tags)) unless tags.nil? || tags.empty?
|
628
|
+
error(403, "no tag params passed")
|
729
629
|
end
|
730
630
|
|
731
631
|
# NB: casts to UTC before converting to a timestamp
|
@@ -737,22 +637,6 @@ module Flapjack
|
|
737
637
|
nil
|
738
638
|
end
|
739
639
|
|
740
|
-
# The passed block will be provided each value from the args
|
741
|
-
# and must return array pairs [key, value] representing members of
|
742
|
-
# the hash this method returns. Keys should be unique -- if they're
|
743
|
-
# not, the earlier pair for that key will be overwritten.
|
744
|
-
def hashify(*args, &block)
|
745
|
-
key_value_pairs = args.map {|a| yield(a) }
|
746
|
-
|
747
|
-
# if using Ruby 1.9,
|
748
|
-
# Hash[ key_value_pairs ]
|
749
|
-
# is all that's needed, but for Ruby 1.8 compatability, these must
|
750
|
-
# be flattened and the resulting array unpacked. flatten(1) only
|
751
|
-
# flattens the arrays constructed in the block, it won't mess up
|
752
|
-
# any values (or keys) that are themselves arrays.
|
753
|
-
Hash[ *( key_value_pairs.flatten(1) )]
|
754
|
-
end
|
755
|
-
|
756
640
|
end
|
757
641
|
|
758
642
|
end
|