flapjack 0.8.10 → 0.8.11

Sign up to get free protection for your applications and to get access to all the features.
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