flapjack 0.8.10 → 0.8.11

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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -0
  3. data/Gemfile +1 -1
  4. data/bin/flapjack +10 -1
  5. data/bin/flapjack-nagios-receiver +1 -2
  6. data/bin/simulate-failed-check +12 -4
  7. data/etc/flapjack_config.yaml.example +2 -1
  8. data/flapjack.gemspec +1 -0
  9. data/lib/flapjack/data/contact.rb +46 -26
  10. data/lib/flapjack/data/entity.rb +28 -0
  11. data/lib/flapjack/data/entity_check.rb +52 -11
  12. data/lib/flapjack/data/event.rb +9 -3
  13. data/lib/flapjack/data/notification_rule.rb +8 -0
  14. data/lib/flapjack/gateways/api.rb +0 -1
  15. data/lib/flapjack/gateways/api/entity_check_presenter.rb +2 -1
  16. data/lib/flapjack/gateways/email.rb +1 -2
  17. data/lib/flapjack/gateways/jabber.rb +3 -3
  18. data/lib/flapjack/gateways/jsonapi.rb +186 -38
  19. data/lib/flapjack/gateways/jsonapi/check_methods.rb +120 -0
  20. data/lib/flapjack/gateways/jsonapi/{entity_check_presenter.rb → check_presenter.rb} +7 -6
  21. data/lib/flapjack/gateways/jsonapi/contact_methods.rb +61 -352
  22. data/lib/flapjack/gateways/jsonapi/entity_methods.rb +117 -248
  23. data/lib/flapjack/gateways/jsonapi/medium_methods.rb +179 -0
  24. data/lib/flapjack/gateways/jsonapi/notification_rule_methods.rb +124 -0
  25. data/lib/flapjack/gateways/jsonapi/pagerduty_credential_methods.rb +128 -0
  26. data/lib/flapjack/gateways/jsonapi/rack/json_params_parser.rb +4 -5
  27. data/lib/flapjack/gateways/jsonapi/report_methods.rb +143 -0
  28. data/lib/flapjack/gateways/web.rb +1 -0
  29. data/lib/flapjack/gateways/web/public/js/backbone.jsonapi.js +165 -101
  30. data/lib/flapjack/gateways/web/public/js/contacts.js +34 -46
  31. data/lib/flapjack/gateways/web/public/js/select2.js +232 -90
  32. data/lib/flapjack/gateways/web/public/js/select2.min.js +4 -4
  33. data/lib/flapjack/gateways/web/views/check.html.erb +11 -2
  34. data/lib/flapjack/processor.rb +6 -6
  35. data/lib/flapjack/version.rb +1 -1
  36. data/spec/lib/flapjack/data/entity_check_spec.rb +1 -1
  37. data/spec/lib/flapjack/data/event_spec.rb +10 -9
  38. data/spec/lib/flapjack/gateways/api/entity_methods_spec.rb +25 -25
  39. data/spec/lib/flapjack/gateways/api_spec.rb +23 -1
  40. data/spec/lib/flapjack/gateways/email_spec.rb +40 -2
  41. data/spec/lib/flapjack/gateways/jabber_spec.rb +1 -1
  42. data/spec/lib/flapjack/gateways/jsonapi/check_methods_spec.rb +134 -0
  43. data/spec/lib/flapjack/gateways/jsonapi/{entity_check_presenter_spec.rb → check_presenter_spec.rb} +17 -17
  44. data/spec/lib/flapjack/gateways/jsonapi/contact_methods_spec.rb +27 -232
  45. data/spec/lib/flapjack/gateways/jsonapi/entity_methods_spec.rb +217 -687
  46. data/spec/lib/flapjack/gateways/jsonapi/medium_methods_spec.rb +232 -0
  47. data/spec/lib/flapjack/gateways/jsonapi/notification_rule_methods_spec.rb +131 -0
  48. data/spec/lib/flapjack/gateways/jsonapi/pagerduty_credential_methods_spec.rb +113 -0
  49. data/spec/lib/flapjack/gateways/jsonapi/report_methods_spec.rb +546 -0
  50. data/spec/lib/flapjack/gateways/jsonapi_spec.rb +10 -1
  51. data/spec/lib/flapjack/gateways/web_spec.rb +1 -0
  52. data/spec/support/jsonapi_helper.rb +62 -0
  53. metadata +36 -8
  54. data/lib/flapjack/gateways/jsonapi/entity_presenter.rb +0 -75
  55. data/spec/lib/flapjack/gateways/jsonapi/entity_presenter_spec.rb +0 -108
@@ -9,10 +9,10 @@ module Flapjack
9
9
 
10
10
  attr_accessor :counter, :id_hash, :tags
11
11
 
12
- attr_reader :check, :summary, :details, :acknowledgement_id
12
+ attr_reader :check, :summary, :details, :acknowledgement_id, :perfdata
13
13
 
14
14
  REQUIRED_KEYS = ['type', 'state', 'entity', 'check', 'summary']
15
- OPTIONAL_KEYS = ['time', 'details', 'acknowledgement_id', 'duration', 'tags']
15
+ OPTIONAL_KEYS = ['time', 'details', 'acknowledgement_id', 'duration', 'tags', 'perfdata']
16
16
 
17
17
  VALIDATIONS = {
18
18
  proc {|e| e['type'].is_a?(String) &&
@@ -42,6 +42,9 @@ module Flapjack
42
42
  proc {|e| e['details'].nil? || e['details'].is_a?(String) } =>
43
43
  "details must be a string",
44
44
 
45
+ proc { |e| e['perfdata'].nil? || e['perfdata'].is_a?(String) } =>
46
+ "perfdata must be a string",
47
+
45
48
  proc {|e| e['acknowledgement_id'].nil? ||
46
49
  e['acknowledgement_id'].is_a?(String) ||
47
50
  e['acknowledgement_id'].is_a?(Integer) } =>
@@ -164,6 +167,7 @@ module Flapjack
164
167
  # 'state' => state,
165
168
  # 'summary' => check_output,
166
169
  # 'details' => check_long_output,
170
+ # 'perfdata' => perf_data,
167
171
  # 'time' => timestamp
168
172
  def self.add(evt, opts = {})
169
173
  raise "Redis connection not set" unless redis = opts[:redis]
@@ -204,11 +208,13 @@ module Flapjack
204
208
 
205
209
  def initialize(attrs = {})
206
210
  ['type', 'state', 'entity', 'check', 'time', 'summary', 'details',
207
- 'acknowledgement_id', 'duration'].each do |key|
211
+ 'perfdata', 'acknowledgement_id', 'duration'].each do |key|
208
212
  instance_variable_set("@#{key}", attrs[key])
209
213
  end
210
214
  # details is optional. set it to nil if it only contains whitespace
211
215
  @details = (@details.is_a?(String) && ! @details.strip.empty?) ? @details.strip : nil
216
+ # perfdata is optional. set it to nil if it only contains whitespace
217
+ @perfdata = (@perfdata.is_a?(String) && ! @perfdata.strip.empty?) ? @perfdata.strip : nil
212
218
  if attrs['tags']
213
219
  @tags = Flapjack::Data::TagSet.new
214
220
  attrs['tags'].each {|tag| @tags.add(tag)}
@@ -81,6 +81,14 @@ module Flapjack
81
81
  }.to_json
82
82
  end
83
83
 
84
+ def to_jsonapi(opts = {})
85
+ self.class.hashify(:id, :tags, :regex_tags, :entities, :regex_entities,
86
+ :time_restrictions, :unknown_media, :warning_media, :critical_media,
87
+ :unknown_blackhole, :warning_blackhole, :critical_blackhole) {|k|
88
+ [k, self.send(k)]
89
+ }.merge(:links => {:contacts => [self.contact_id]}).to_json
90
+ end
91
+
84
92
  # entity names match?
85
93
  def match_entity?(event_id)
86
94
  return false unless @entities
@@ -104,7 +104,6 @@ module Flapjack
104
104
  end
105
105
 
106
106
  register Flapjack::Gateways::API::EntityMethods
107
-
108
107
  register Flapjack::Gateways::API::ContactMethods
109
108
 
110
109
  not_found do
@@ -24,6 +24,7 @@ module Flapjack
24
24
  'enabled' => @entity_check.enabled?,
25
25
  'summary' => @entity_check.summary,
26
26
  'details' => @entity_check.details,
27
+ 'perfdata' => @entity_check.perfdata,
27
28
  'in_unscheduled_maintenance' => @entity_check.in_unscheduled_maintenance?,
28
29
  'in_scheduled_maintenance' => @entity_check.in_scheduled_maintenance?,
29
30
  'last_update' => @entity_check.last_update,
@@ -214,4 +215,4 @@ module Flapjack
214
215
 
215
216
  end
216
217
 
217
- end
218
+ end
@@ -51,6 +51,7 @@ module Flapjack
51
51
  host = @smtp_config ? @smtp_config['host'] : nil
52
52
  port = @smtp_config ? @smtp_config['port'] : nil
53
53
  starttls = @smtp_config ? !! @smtp_config['starttls'] : nil
54
+ m_from = @smtp_config ? @smtp_config['from'] : "flapjack@#{@fqdn}"
54
55
  if @smtp_config
55
56
  if auth_config = @smtp_config['auth']
56
57
  auth = {}
@@ -60,7 +61,6 @@ module Flapjack
60
61
  end
61
62
  end
62
63
 
63
- m_from = "flapjack@#{@fqdn}"
64
64
  @logger.debug("flapjack_mailer: set from to #{m_from}")
65
65
 
66
66
  mail = prepare_email(:from => m_from,
@@ -176,4 +176,3 @@ module Flapjack
176
176
  end
177
177
  end
178
178
  end
179
-
@@ -189,7 +189,7 @@ module Flapjack
189
189
  four_hours = 4 * 60 * 60
190
190
  duration = (dur.nil? || (dur <= 0)) ? four_hours : dur
191
191
 
192
- event_id = @redis.hget('check_hashes', ackid)
192
+ event_id = @redis.hget('checks_by_hash', ackid)
193
193
 
194
194
  if event_id.nil?
195
195
  error = "not found"
@@ -394,7 +394,7 @@ module Flapjack
394
394
  )
395
395
  end
396
396
  end
397
- msg = failing_list.inject("Ack list:\n") {|memo,kv|
397
+ msg = entities.inject("Ack list:\n") {|memo,kv|
398
398
  kv[1].each {|e| memo << "#{kv[0]}:#{e}\n" }
399
399
  memo
400
400
  }
@@ -475,7 +475,7 @@ module Flapjack
475
475
  )
476
476
  end
477
477
  end
478
- msg = failing_list.inject("Ack list:\n") {|memo,kv|
478
+ msg = my_failing_checks.inject("Ack list:\n") {|memo,kv|
479
479
  kv[1].each {|e| memo << "#{kv[0]}:#{e}\n" }
480
480
  memo
481
481
  }
@@ -16,8 +16,13 @@ require 'flapjack/redis_pool'
16
16
 
17
17
  require 'flapjack/gateways/jsonapi/rack/json_params_parser'
18
18
 
19
+ require 'flapjack/gateways/jsonapi/check_methods'
19
20
  require 'flapjack/gateways/jsonapi/contact_methods'
20
21
  require 'flapjack/gateways/jsonapi/entity_methods'
22
+ require 'flapjack/gateways/jsonapi/medium_methods'
23
+ require 'flapjack/gateways/jsonapi/notification_rule_methods'
24
+ require 'flapjack/gateways/jsonapi/pagerduty_credential_methods'
25
+ require 'flapjack/gateways/jsonapi/report_methods'
21
26
 
22
27
  module Flapjack
23
28
 
@@ -28,6 +33,10 @@ module Flapjack
28
33
  include Flapjack::Utility
29
34
 
30
35
  JSON_REQUEST_MIME_TYPES = ['application/vnd.api+json', 'application/json', 'application/json-patch+json']
36
+ # http://www.iana.org/assignments/media-types/application/vnd.api+json
37
+ JSONAPI_MEDIA_TYPE = 'application/vnd.api+json; charset=utf-8'
38
+ # http://tools.ietf.org/html/rfc6902
39
+ JSON_PATCH_MEDIA_TYPE = 'application/json-patch+json; charset=utf-8'
31
40
 
32
41
  class ContactNotFound < RuntimeError
33
42
  attr_reader :contact_id
@@ -57,6 +66,13 @@ module Flapjack
57
66
  end
58
67
  end
59
68
 
69
+ class EntitiesNotFound < RuntimeError
70
+ attr_reader :entity_ids
71
+ def initialize(entity_ids)
72
+ @entity_ids = entity_ids
73
+ end
74
+ end
75
+
60
76
  class EntityCheckNotFound < RuntimeError
61
77
  attr_reader :entity, :check
62
78
  def initialize(entity, check)
@@ -209,62 +225,194 @@ module Flapjack
209
225
  end
210
226
  end
211
227
 
212
- def is_json_request?
213
- Flapjack::Gateways::JSONAPI::JSON_REQUEST_MIME_TYPES.include?(request.content_type.split(/\s*[;,]\s*/, 2).first.downcase)
214
- end
228
+ module Helpers
229
+
230
+ def cors_headers
231
+ allow_headers = %w(* Content-Type Accept AUTHORIZATION Cache-Control)
232
+ allow_methods = %w(GET POST PUT PATCH DELETE OPTIONS)
233
+ expose_headers = %w(Cache-Control Content-Language Content-Type Expires Last-Modified Pragma)
234
+ cors_headers = {
235
+ 'Access-Control-Allow-Origin' => '*',
236
+ 'Access-Control-Allow-Methods' => allow_methods.join(', '),
237
+ 'Access-Control-Allow-Headers' => allow_headers.join(', '),
238
+ 'Access-Control-Expose-Headers' => expose_headers.join(', '),
239
+ 'Access-Control-Max-Age' => '1728000'
240
+ }
241
+ headers(cors_headers)
242
+ end
215
243
 
216
- def is_jsonpatch_request?
217
- 'application/json-patch+json'.eql?(request.content_type.split(/\s*[;,]\s*/, 2).first.downcase)
218
- end
244
+ def location(ids)
245
+ location = "#{base_url}#{request.path_info}#{ids.length == 1 ? '/' + ids.first : '?ids=' + ids.join(',')}"
246
+ headers({'Location' => location})
247
+ end
219
248
 
220
- register Flapjack::Gateways::JSONAPI::EntityMethods
249
+ def err(status, *msg)
250
+ msg_str = msg.join(", ")
251
+ logger.info "Error: #{msg_str}"
252
+ [status, {}, {:errors => msg}.to_json]
253
+ end
221
254
 
222
- register Flapjack::Gateways::JSONAPI::ContactMethods
255
+ def is_json_request?
256
+ Flapjack::Gateways::JSONAPI::JSON_REQUEST_MIME_TYPES.include?(request.content_type.split(/\s*[;,]\s*/, 2).first)
257
+ end
223
258
 
224
- # the following should add the cors headers to every request, but is no work
225
- #register Sinatra::CrossOrigin
226
- #
227
- #configure do
228
- # enable :cross_origin
229
- #end
230
- #set :allow_origin, :any
231
- #set :allow_methods, [:get, :post, :put, :patch, :delete, :options]
259
+ def is_jsonapi_request?
260
+ return false if request.content_type.nil?
261
+ 'application/vnd.api+json'.eql?(request.content_type.split(/\s*[;,]\s*/, 2).first)
262
+ end
263
+
264
+ def is_jsonpatch_request?
265
+ return false if request.content_type.nil?
266
+ 'application/json-patch+json'.eql?(request.content_type.split(/\s*[;,]\s*/, 2).first)
267
+ end
268
+
269
+ def wrapped_params(name, error_on_nil = true)
270
+ result = params[name.to_sym]
271
+ if result.nil?
272
+ if error_on_nil
273
+ logger.debug("No '#{name}' object found in the following supplied JSON:")
274
+ logger.debug(request.body.is_a?(StringIO) ? request.body.read : request.body)
275
+ halt err(403, "No '#{name}' object received")
276
+ else
277
+ result = [{}]
278
+ end
279
+ end
280
+ unless result.is_a?(Array)
281
+ halt err(403, "The received '#{name}'' object is not an Array")
282
+ end
283
+ result
284
+ end
285
+
286
+ def find_contact(contact_id)
287
+ contact = Flapjack::Data::Contact.find_by_id(contact_id, :logger => logger, :redis => redis)
288
+ raise Flapjack::Gateways::JSONAPI::ContactNotFound.new(contact_id) if contact.nil?
289
+ contact
290
+ end
291
+
292
+ def find_rule(rule_id)
293
+ rule = Flapjack::Data::NotificationRule.find_by_id(rule_id, :logger => logger, :redis => redis)
294
+ raise Flapjack::Gateways::JSONAPI::NotificationRuleNotFound.new(rule_id) if rule.nil?
295
+ rule
296
+ end
297
+
298
+ def find_tags(tags)
299
+ halt err(400, "no tags given") if tags.nil? || tags.empty?
300
+ tags
301
+ end
302
+
303
+ def find_entity(entity_name)
304
+ entity = Flapjack::Data::Entity.find_by_name(entity_name, :redis => redis)
305
+ raise Flapjack::Gateways::JSONAPI::EntityNotFound.new(entity_name) if entity.nil?
306
+ entity
307
+ end
308
+
309
+ def find_entity_by_id(entity_id)
310
+ entity = Flapjack::Data::Entity.find_by_id(entity_id, :redis => redis)
311
+ raise Flapjack::Gateways::JSONAPI::EntityNotFound.new(entity_id) if entity.nil?
312
+ entity
313
+ end
314
+
315
+ def find_entity_check(entity, check_name)
316
+ entity_check = Flapjack::Data::EntityCheck.for_entity(entity, check_name, :redis => redis)
317
+ raise Flapjack::Gateways::JSONAPI::EntityCheckNotFound.new(entity.name, check_name) if entity_check.nil?
318
+ entity_check
319
+ end
320
+
321
+ def find_entity_check_by_name(entity_name, check_name)
322
+ entity_check = Flapjack::Data::EntityCheck.for_entity_name(entity_name, check_name, :redis => redis)
323
+ raise Flapjack::Gateways::JSONAPI::EntityCheckNotFound.new(entity_name, check_name) if entity_check.nil?
324
+ entity_check
325
+ end
326
+
327
+ def apply_json_patch(object_path, &block)
328
+ ops = params[:ops]
329
+
330
+ if ops.nil? || !ops.is_a?(Array)
331
+ halt err(400, "Invalid JSON-Patch request")
332
+ end
333
+
334
+ ops.each do |operation|
335
+ linked = nil
336
+ property = nil
337
+
338
+ op = operation['op']
339
+ operation['path'] =~ /\A\/#{object_path}\/0\/([^\/]+)(?:\/([^\/]+)(?:\/([^\/]+))?)?\z/
340
+ if 'links'.eql?($1)
341
+ linked = $2
342
+
343
+ value = case op
344
+ when 'add'
345
+ operation['value']
346
+ when 'remove'
347
+ $3
348
+ end
349
+ elsif 'replace'.eql?(op)
350
+ property = $1
351
+ value = operation['value']
352
+ else
353
+ next
354
+ end
355
+
356
+ yield(op, property, linked, value)
357
+ end
358
+ end
359
+
360
+ # NB: casts to UTC before converting to a timestamp
361
+ def validate_and_parsetime(value)
362
+ return unless value
363
+ Time.iso8601(value).getutc.to_i
364
+ rescue ArgumentError => e
365
+ logger.error "Couldn't parse time from '#{value}'"
366
+ nil
367
+ end
368
+
369
+ end
232
370
 
233
371
  options '*' do
234
372
  cors_headers
235
373
  204
236
374
  end
237
375
 
238
- not_found do
239
- err(404, "not routable")
376
+ # The following catch-all routes act as impromptu filters for their method types
377
+ get '*' do
378
+ content_type JSONAPI_MEDIA_TYPE
379
+ cors_headers
380
+ pass
240
381
  end
241
382
 
242
- def cors_headers
243
- allow_headers = %w(* Content-Type Accept AUTHORIZATION Cache-Control)
244
- allow_methods = %w(GET POST PUT PATCH DELETE OPTIONS)
245
- expose_headers = %w(Cache-Control Content-Language Content-Type Expires Last-Modified Pragma)
246
- cors_headers = {
247
- 'Access-Control-Allow-Origin' => '*',
248
- 'Access-Control-Allow-Methods' => allow_methods.join(', '),
249
- 'Access-Control-Allow-Headers' => allow_headers.join(', '),
250
- 'Access-Control-Expose-Headers' => expose_headers.join(', '),
251
- 'Access-Control-Max-Age' => '1728000'
252
- }
253
- headers(cors_headers)
383
+ # bare 'params' may have splat/captures for regex route, see
384
+ # https://github.com/sinatra/sinatra/issues/453
385
+ post '*' do
386
+ halt(405) unless request.params.empty? || is_json_request? || is_jsonapi_request
387
+ content_type JSONAPI_MEDIA_TYPE
388
+ cors_headers
389
+ pass
390
+ end
391
+
392
+ patch '*' do
393
+ halt(405) unless is_jsonpatch_request?
394
+ content_type JSONAPI_MEDIA_TYPE
395
+ cors_headers
396
+ pass
254
397
  end
255
398
 
256
- def location(ids)
257
- location = "#{base_url}#{request.path_info}#{ids.length == 1 ? '/' + ids.first : '?ids=' + ids.join(',')}"
258
- headers({'Location' => location})
399
+ delete '*' do
400
+ cors_headers
401
+ pass
259
402
  end
260
403
 
261
- private
404
+ register Flapjack::Gateways::JSONAPI::CheckMethods
405
+ register Flapjack::Gateways::JSONAPI::ContactMethods
406
+ register Flapjack::Gateways::JSONAPI::EntityMethods
407
+ register Flapjack::Gateways::JSONAPI::MediumMethods
408
+ register Flapjack::Gateways::JSONAPI::NotificationRuleMethods
409
+ register Flapjack::Gateways::JSONAPI::PagerdutyCredentialMethods
410
+ register Flapjack::Gateways::JSONAPI::ReportMethods
262
411
 
263
- def err(status, *msg)
264
- msg_str = msg.join(", ")
265
- logger.info "Error: #{msg_str}"
266
- [status, {}, {:errors => msg}.to_json]
412
+ not_found do
413
+ err(404, "not routable")
267
414
  end
415
+
268
416
  end
269
417
 
270
418
  end
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'sinatra/base'
4
+
5
+ require 'flapjack/data/event'
6
+
7
+ module Flapjack
8
+
9
+ module Gateways
10
+
11
+ class JSONAPI < Sinatra::Base
12
+
13
+ module CheckMethods
14
+
15
+ module Helpers
16
+
17
+ def checks_for_check_names(check_names)
18
+ return if check_names.nil?
19
+ entity_cache = {}
20
+ check_names.inject([]) do |memo, check_name|
21
+ entity_name, check = check_name.split(':', 2)
22
+ entity = (entity_cache[entity_name] ||= find_entity(entity_name))
23
+ memo << find_entity_check(entity, check)
24
+ memo
25
+ end
26
+ end
27
+
28
+ end
29
+
30
+ def self.registered(app)
31
+ app.helpers Flapjack::Gateways::JSONAPI::Helpers
32
+ app.helpers Flapjack::Gateways::JSONAPI::CheckMethods::Helpers
33
+
34
+ # create a scheduled maintenance period for a check on an entity
35
+ app.post %r{^/scheduled_maintenances/checks/([^/]+)$} do
36
+ scheduled_maintenances = wrapped_params('scheduled_maintenances')
37
+ checks_for_check_names(params[:captures][0].split(',')).each do |check|
38
+ scheduled_maintenances.each do |wp|
39
+ start_time = validate_and_parsetime(wp['start_time'])
40
+ halt( err(403, "start time must be provided") ) unless start_time
41
+
42
+ check.create_scheduled_maintenance(start_time,
43
+ wp[:duration].to_i, :summary => wp[:summary])
44
+ end
45
+ end
46
+
47
+ status 204
48
+ end
49
+
50
+ # create an acknowledgement for a service on an entity
51
+ # NB currently, this does not acknowledge a specific failure event, just
52
+ # the entity-check as a whole
53
+ app.post %r{^/unscheduled_maintenances/checks/([^/]+)$} do
54
+ unscheduled_maintenances = wrapped_params('unscheduled_maintenances', false)
55
+ checks_for_check_names(params[:captures][0].split(',')).each do |check|
56
+ unscheduled_maintenances.each do |wp|
57
+ dur = wp['duration'] ? wp['duration'].to_i : nil
58
+ duration = (dur.nil? || (dur <= 0)) ? (4 * 60 * 60) : dur
59
+ summary = wp['summary']
60
+
61
+ opts = {:duration => duration}
62
+ opts[:summary] = summary if summary
63
+
64
+ Flapjack::Data::Event.create_acknowledgement(
65
+ check.entity_name, check.check, {:redis => redis}.merge(opts))
66
+ end
67
+ end
68
+
69
+ status 204
70
+ end
71
+
72
+ app.patch %r{^/unscheduled_maintenances/checks/([^/]+)$} do
73
+ checks_for_check_names(params[:captures][0].split(',')).each do |check|
74
+ apply_json_patch('unscheduled_maintenances') do |op, property, linked, value|
75
+ case op
76
+ when 'replace'
77
+ if ['end_time'].include?(property)
78
+ end_time = validate_and_parsetime(value)
79
+ check.end_unscheduled_maintenance(end_time.to_i)
80
+ end
81
+ end
82
+ end
83
+ end
84
+ status 204
85
+ end
86
+
87
+ app.delete %r{^/scheduled_maintenances/checks/([^/]+)$} do
88
+ start_time = validate_and_parsetime(params[:start_time])
89
+ halt( err(403, "start time must be provided") ) unless start_time
90
+
91
+ checks_for_check_names(params[:captures][0].split(',')).each do |check|
92
+ check.end_scheduled_maintenance(start_time.to_i)
93
+ end
94
+ status 204
95
+ end
96
+
97
+ app.post %r{^/test_notifications/checks/([^/]+)$} do
98
+ test_notifications = wrapped_params('test_notifications', false)
99
+ checks_for_check_names(params[:captures][0].split(',')).each do |check|
100
+ test_notifications.each do |wp|
101
+ summary = wp['summary'] ||
102
+ "Testing notifications to all contacts interested in entity #{check.entity.name}"
103
+ Flapjack::Data::Event.test_notifications(
104
+ check.entity_name, check.check,
105
+ :summary => summary,
106
+ :redis => redis)
107
+ end
108
+ end
109
+ status 204
110
+ end
111
+
112
+ end
113
+
114
+ end
115
+
116
+ end
117
+
118
+ end
119
+
120
+ end