flapjack 1.1.0 → 1.2.0rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.ruby-version +1 -1
  4. data/.travis.yml +12 -7
  5. data/CHANGELOG.md +12 -0
  6. data/Gemfile +6 -2
  7. data/Gemfile-ruby1.9 +29 -0
  8. data/Gemfile-ruby1.9.lock +251 -0
  9. data/README.md +2 -2
  10. data/Rakefile +1 -0
  11. data/etc/flapjack_config.yaml.example +2 -2
  12. data/features/steps/events_steps.rb +2 -2
  13. data/features/steps/flapjack-netsaint-parser_steps.rb +1 -1
  14. data/features/support/env.rb +1 -6
  15. data/lib/flapjack/cli/import.rb +2 -5
  16. data/lib/flapjack/cli/purge.rb +4 -4
  17. data/lib/flapjack/cli/receiver.rb +122 -54
  18. data/lib/flapjack/cli/server.rb +0 -5
  19. data/lib/flapjack/coordinator.rb +6 -0
  20. data/lib/flapjack/data/contact.rb +10 -62
  21. data/lib/flapjack/data/entity.rb +36 -52
  22. data/lib/flapjack/data/entity_check.rb +90 -21
  23. data/lib/flapjack/data/event.rb +4 -5
  24. data/lib/flapjack/data/notification.rb +8 -10
  25. data/lib/flapjack/data/notification_rule.rb +32 -35
  26. data/lib/flapjack/data/tagged.rb +48 -0
  27. data/lib/flapjack/gateways/jabber.rb +4 -5
  28. data/lib/flapjack/gateways/jsonapi/check_methods.rb +45 -7
  29. data/lib/flapjack/gateways/jsonapi/check_presenter.rb +1 -1
  30. data/lib/flapjack/gateways/jsonapi/contact_methods.rb +8 -2
  31. data/lib/flapjack/gateways/jsonapi/entity_methods.rb +26 -8
  32. data/lib/flapjack/gateways/jsonapi/medium_methods.rb +13 -9
  33. data/lib/flapjack/gateways/jsonapi/metrics_methods.rb +2 -2
  34. data/lib/flapjack/gateways/jsonapi/notification_rule_methods.rb +1 -1
  35. data/lib/flapjack/gateways/jsonapi/pagerduty_credential_methods.rb +24 -17
  36. data/lib/flapjack/gateways/jsonapi/rack/json_params_parser.rb +1 -1
  37. data/lib/flapjack/gateways/jsonapi/report_methods.rb +4 -4
  38. data/lib/flapjack/gateways/jsonapi.rb +52 -31
  39. data/lib/flapjack/gateways/oobetet.rb +2 -3
  40. data/lib/flapjack/gateways/pagerduty.rb +9 -8
  41. data/lib/flapjack/gateways/web/public/js/backbone.jsonapi.js +19 -0
  42. data/lib/flapjack/gateways/web/public/js/flapjack.js +6 -2
  43. data/lib/flapjack/gateways/web/public/js/modules/contact.js +9 -14
  44. data/lib/flapjack/gateways/web/public/js/modules/medium.js +1 -0
  45. data/lib/flapjack/gateways/web/public/js/self_stats.js +1 -1
  46. data/lib/flapjack/gateways/web/views/edit_contacts.html.erb +3 -3
  47. data/lib/flapjack/gateways/web.rb +8 -7
  48. data/lib/flapjack/notifier.rb +2 -4
  49. data/lib/flapjack/processor.rb +2 -2
  50. data/lib/flapjack/version.rb +1 -1
  51. data/lib/flapjack.rb +10 -0
  52. data/spec/lib/flapjack/coordinator_spec.rb +18 -0
  53. data/spec/lib/flapjack/data/contact_spec.rb +4 -12
  54. data/spec/lib/flapjack/data/entity_check_spec.rb +56 -3
  55. data/spec/lib/flapjack/data/entity_spec.rb +79 -67
  56. data/spec/lib/flapjack/data/event_spec.rb +78 -78
  57. data/spec/lib/flapjack/data/notification_rule_spec.rb +4 -2
  58. data/spec/lib/flapjack/gateways/jsonapi/check_methods_spec.rb +94 -11
  59. data/spec/lib/flapjack/gateways/jsonapi/entity_methods_spec.rb +84 -0
  60. data/spec/lib/flapjack/gateways/pagerduty_spec.rb +5 -3
  61. data/spec/lib/flapjack/gateways/web_spec.rb +3 -3
  62. data/spec/service_consumers/pact_helper.rb +74 -0
  63. data/spec/service_consumers/pacts/flapjack-diner_v1.0.json +4522 -0
  64. data/spec/service_consumers/provider_states_for_flapjack-diner.rb +356 -0
  65. data/spec/spec_helper.rb +0 -8
  66. data/spec/support/jsonapi_helper.rb +1 -1
  67. data/tasks/benchmarks.rake +6 -3
  68. data/tasks/profile.rake +1 -1
  69. data/tmp/acknowledge.rb +0 -3
  70. data/tmp/create_event_ok.rb +0 -3
  71. data/tmp/create_event_unknown.rb +0 -3
  72. data/tmp/create_events_failure.rb +0 -3
  73. data/tmp/create_events_ok.rb +0 -3
  74. data/tmp/create_events_ok_fail_ack_ok.rb +0 -3
  75. data/tmp/create_events_ok_failure.rb +2 -5
  76. data/tmp/create_events_ok_failure_ack.rb +0 -3
  77. data/tmp/test_json_post.rb +4 -3
  78. data/tmp/test_notification_rules_api.rb +2 -3
  79. metadata +13 -8
  80. data/lib/flapjack/data/tag.rb +0 -61
  81. data/lib/flapjack/data/tag_set.rb +0 -16
  82. data/spec/lib/flapjack/data/tag_spec.rb +0 -36
@@ -66,10 +66,16 @@ module Flapjack
66
66
  raise Flapjack::Gateways::JSONAPI::EntitiesNotFound.new(requested_entities)
67
67
  end
68
68
 
69
- linked_contact_ids = entities.empty? ? [] : Flapjack::Data::Entity.contact_ids_for(entities.map(&:id), :redis => redis)
69
+ entity_ids = entities.map(&:id)
70
+ linked_contact_ids = entities.empty? ? [] :
71
+ Flapjack::Data::Entity.contact_ids_for(entity_ids, :redis => redis)
72
+ linked_check_ids = entities.empty? ? [] :
73
+ Flapjack::Data::Entity.check_ids_for(entity_ids, :redis => redis)
70
74
 
71
75
  entities_json = entities.collect {|entity|
72
- entity.to_jsonapi(:contact_ids => linked_contact_ids[entity.id])
76
+ entity_id = entity.id
77
+ entity.to_jsonapi(:contact_ids => linked_contact_ids[entity_id],
78
+ :check_ids => linked_check_ids[entity_id] )
73
79
  }.join(",")
74
80
 
75
81
  '{"entities":[' + entities_json + ']}'
@@ -86,7 +92,7 @@ module Flapjack
86
92
 
87
93
  response.headers['Location'] = "#{request.base_url}/entities/#{entity_ids.join(',')}"
88
94
  status 201
89
- entity_ids.to_json
95
+ Flapjack.dump_json(entity_ids)
90
96
  end
91
97
 
92
98
  app.patch '/entities/:id' do
@@ -96,19 +102,31 @@ module Flapjack
96
102
  apply_json_patch('entities') do |op, property, linked, value|
97
103
  case op
98
104
  when 'replace'
99
- if ['name'].include?(property)
100
- # # Name change not supported in Flapjack v1.x, too many changes required
101
- # entity.update(property => value)
105
+ if 'name'.eql?(property)
106
+ name = entity.name
107
+ if name != value
108
+ existing = Flapjack::Data::Entity.find_by_name(value, :redis => redis)
109
+ Flapjack::Data::Entity.send(existing.nil? ? :rename : :merge,
110
+ name, value, :redis => redis)
111
+ end
102
112
  end
103
113
  when 'add'
104
- if 'contacts'.eql?(linked)
114
+ case linked
115
+ when 'contacts'
105
116
  contact = Flapjack::Data::Contact.find_by_id(value, :redis => redis)
106
117
  contact.add_entity(entity) unless contact.nil?
118
+ when 'tags'
119
+ value.respond_to?(:each) ? entity.add_tags(*value) :
120
+ entity.add_tags(value)
107
121
  end
108
122
  when 'remove'
109
- if 'contacts'.eql?(linked)
123
+ case linked
124
+ when 'contacts'
110
125
  contact = Flapjack::Data::Contact.find_by_id(value, :redis => redis)
111
126
  contact.remove_entity(entity) unless contact.nil?
127
+ when 'tags'
128
+ value.respond_to?(:each) ? entity.delete_tags(*value) :
129
+ entity.delete_tags(value)
112
130
  end
113
131
  end
114
132
  end
@@ -42,8 +42,8 @@ module Flapjack
42
42
 
43
43
  contact_id = $1
44
44
  media_type = $2
45
- halt err(422, "Could not get contact_id from media_id") if contact_id.nil?
46
- halt err(422, "Could not get media type from media_id") if media_type.nil?
45
+ halt err(422, "Could not get contact_id from media_id '#{m_id}'") if contact_id.nil?
46
+ halt err(422, "Could not get media type from media_id '#{m_id}'") if media_type.nil?
47
47
 
48
48
  contact_cache[contact_id] ||= find_contact(contact_id)
49
49
 
@@ -65,15 +65,17 @@ module Flapjack
65
65
  halt err(422, "No valid media were submitted")
66
66
  end
67
67
 
68
- unless media_data.all? {|m| m['id'].nil? }
69
- halt err(422, "Media creation cannot include IDs")
68
+ media_id_re = /^#{params[:contact_id]}_(?:#{Flapjack::Data::Contact::ALL_MEDIA.join('|')}$)/
69
+
70
+ unless media_data.all? {|m| m['id'].nil? || media_id_re === m['id'] }
71
+ halt err(422, "Media creation cannot include non-conformant IDs")
70
72
  end
71
73
 
72
74
  semaphore = obtain_semaphore(SEMAPHORE_CONTACT_MASS_UPDATE)
73
75
  contact = Flapjack::Data::Contact.find_by_id(params[:contact_id], :redis => redis)
74
76
  if contact.nil?
75
77
  semaphore.release
76
- halt err(422, "Contact id:'#{params[:contact_id]}' could not be loaded")
78
+ halt err(422, "Contact id: '#{params[:contact_id]}' could not be loaded")
77
79
  end
78
80
 
79
81
  media_data.each do |medium_data|
@@ -90,7 +92,7 @@ module Flapjack
90
92
 
91
93
  status 201
92
94
  response.headers['Location'] = "#{base_url}/media/#{media_ids.join(',')}"
93
- media_ids.to_json
95
+ Flapjack.dump_json(media_ids)
94
96
  end
95
97
 
96
98
  # get one or more media records; media ids are, for Flapjack
@@ -115,19 +117,21 @@ module Flapjack
115
117
  media_list_cache[contact.id] ||= contact.media_list
116
118
  if media_list_cache[contact.id].include?(media_type)
117
119
  medium_id = "#{contact.id}_#{media_type}"
120
+ int = contact.media_intervals[media_type]
121
+ rut = contact.media_rollup_thresholds[media_type]
118
122
  memo <<
119
123
  {:id => medium_id,
120
124
  :type => media_type,
121
125
  :address => contact.media[media_type],
122
- :interval => contact.media_intervals[media_type],
123
- :rollup_threshold => contact.media_rollup_thresholds[media_type],
126
+ :interval => int.nil? ? nil : int.to_i,
127
+ :rollup_threshold => rut.nil? ? nil : rut.to_i,
124
128
  :links => {:contacts => [contact.id]}}
125
129
  end
126
130
 
127
131
  memo
128
132
  end
129
133
 
130
- '{"media":' + media_data.to_json + '}'
134
+ '{"media":' + Flapjack.dump_json(media_data) + '}'
131
135
  end
132
136
 
133
137
  # update one or more media records; media ids are, for Flapjack
@@ -50,7 +50,7 @@ module Flapjack
50
50
  {
51
51
  'all' => Flapjack::Data::Entity.all(:redis => redis).length,
52
52
  'enabled' => Flapjack::Data::Entity.all(:enabled => true, :redis => redis).length,
53
- 'failing' => Flapjack::Data::Entity.find_all_with_failing_checks(:redis => redis).length,
53
+ 'failing' => Flapjack::Data::Entity.find_all_names_with_failing_checks(:redis => redis).length,
54
54
  }
55
55
  end
56
56
 
@@ -88,7 +88,7 @@ module Flapjack
88
88
  metrics[key] = self.send(key.to_sym)
89
89
  end
90
90
 
91
- return metrics.to_json
91
+ Flapjack.dump_json(metrics)
92
92
  end
93
93
  end
94
94
 
@@ -67,7 +67,7 @@ module Flapjack
67
67
 
68
68
  unless rule_ids.empty?
69
69
  response.headers['Location'] = "#{base_url}/notification_rules/#{rule_ids.join(',')}"
70
- rule_ids.to_json
70
+ Flapjack.dump_json(rule_ids)
71
71
  end
72
72
  end
73
73
 
@@ -46,7 +46,7 @@ module Flapjack
46
46
  contact = Flapjack::Data::Contact.find_by_id(params[:contact_id], :redis => redis)
47
47
  if contact.nil?
48
48
  semaphore.release
49
- halt err(422, "Contact id '#{params[:contact_id]}' could not be loaded")
49
+ halt err(422, "Contact id: '#{params[:contact_id]}' could not be loaded")
50
50
  end
51
51
 
52
52
  pagerduty_credential_data = fields.inject({}) do |memo, field|
@@ -61,7 +61,7 @@ module Flapjack
61
61
 
62
62
  status 201
63
63
  response.headers['Location'] = "#{base_url}/pagerduty_credentials/#{contact.id}"
64
- [contact.id].to_json
64
+ Flapjack.dump_json([contact.id])
65
65
  end
66
66
 
67
67
  app.get %r{^/pagerduty_credentials(?:/)?([^/]+)?$} do
@@ -72,14 +72,18 @@ module Flapjack
72
72
  end
73
73
 
74
74
  pagerduty_credentials_data = contacts.inject([]) do |memo, contact|
75
- pdc = contact.pagerduty_credentials.clone
75
+ pdc = contact.pagerduty_credentials
76
+
77
+ unless pdc.nil?
78
+ pd_data = pdc.clone
79
+ pd_data['links'] = {'contacts' => [contact.id]}
80
+ memo << pd_data
81
+ end
76
82
 
77
- pdc['links'] = {'contacts' => [contact.id]}
78
- memo << pdc
79
83
  memo
80
84
  end
81
85
 
82
- '{"pagerduty_credentials":' + pagerduty_credentials_data.to_json + '}'
86
+ '{"pagerduty_credentials":' + Flapjack.dump_json(pagerduty_credentials_data) + '}'
83
87
  end
84
88
 
85
89
  # update one or more sets of pagerduty credentials
@@ -88,21 +92,22 @@ module Flapjack
88
92
  apply_json_patch('pagerduty_credentials') do |op, property, linked, value|
89
93
  if 'replace'.eql?(op)
90
94
 
91
- pdc = contact.pagerduty_credentials.clone
95
+ pdc = contact.pagerduty_credentials
96
+ pd_data = pdc.nil? ? {} : pdc.clone
92
97
 
93
98
  case property
94
99
  when 'service_key'
95
- pdc['service_key'] = value
96
- contact.set_pagerduty_credentials(pdc)
100
+ pd_data['service_key'] = value
101
+ contact.set_pagerduty_credentials(pd_data)
97
102
  when 'subdomain'
98
- pdc['subdomain'] = value
99
- contact.set_pagerduty_credentials(pdc)
103
+ pd_data['subdomain'] = value
104
+ contact.set_pagerduty_credentials(pd_data)
100
105
  when 'username'
101
- pdc['username'] = value
102
- contact.set_pagerduty_credentials(pdc)
106
+ pd_data['username'] = value
107
+ contact.set_pagerduty_credentials(pd_data)
103
108
  when 'password'
104
- pdc['password'] = value
105
- contact.set_pagerduty_credentials(pdc)
109
+ pd_data['password'] = value
110
+ contact.set_pagerduty_credentials(pd_data)
106
111
  end
107
112
  end
108
113
  end
@@ -112,9 +117,11 @@ module Flapjack
112
117
  end
113
118
 
114
119
  app.delete '/pagerduty_credentials/:contact_id' do
115
- params[:contact_id].split(',').uniq.collect {|c_id| find_contact(c_id) }.each do |contact|
120
+ params[:contact_id].split(',').uniq.collect {|c_id|
121
+ find_contact(c_id)
122
+ }.each {|contact|
116
123
  contact.delete_pagerduty_credentials
117
- end
124
+ }
118
125
  status 204
119
126
  end
120
127
 
@@ -13,7 +13,7 @@ module Flapjack
13
13
  env['rack.request.form_input'] = env['rack.input']
14
14
  json_data = env['rack.input'].read
15
15
  env['rack.input'].rewind
16
- data = json_data.empty? ? {} : Oj.load(json_data)
16
+ data = json_data.empty? ? {} : Flapjack.load_json(json_data)
17
17
  env['rack.request.form_hash'] = data.empty? ? {} :
18
18
  (('application/json-patch+json'.eql?(t)) ? {'ops' => data} : data)
19
19
  end
@@ -27,7 +27,7 @@ module Flapjack
27
27
  end
28
28
 
29
29
  checks = if event_ids.nil?
30
- Flapjack::Data::EntityCheck.find_current(:redis => redis).collect {|check_name|
30
+ Flapjack::Data::EntityCheck.find_current_names(:redis => redis).collect {|check_name|
31
31
  find_entity_check_by_name(*check_name.split(':', 2))
32
32
  }
33
33
  elsif !event_ids.empty?
@@ -121,9 +121,9 @@ module Flapjack
121
121
  }
122
122
  end
123
123
 
124
- "{\"#{action}_reports\":" + report_data.to_json + "," +
125
- "\"linked\":{\"entities\":" + entity_data.to_json + "," +
126
- "\"checks\":" + check_data.to_json + "}}"
124
+ "{\"#{action}_reports\":" + Flapjack.dump_json(report_data) + "," +
125
+ "\"linked\":{\"entities\":" + Flapjack.dump_json(entity_data) + "," +
126
+ "\"checks\":" + Flapjack.dump_json(check_data) + "}}"
127
127
  end
128
128
 
129
129
  end
@@ -89,6 +89,13 @@ module Flapjack
89
89
  end
90
90
  end
91
91
 
92
+ class EntityChecksNotFound < RuntimeError
93
+ attr_reader :entity_checks
94
+ def initialize(entity_checks)
95
+ @entity_checks = entity_checks
96
+ end
97
+ end
98
+
92
99
  class ResourceLocked < RuntimeError
93
100
  attr_reader :resource
94
101
  def initialize(resource)
@@ -100,37 +107,45 @@ module Flapjack
100
107
 
101
108
  set :protection, :except => :path_traversal
102
109
 
103
- rescue_error = Proc.new {|status, exception, request_info, *msg|
104
- if !msg || msg.empty?
105
- trace = exception.backtrace.join("\n")
106
- msg = "#{exception.class} - #{exception.message}"
107
- msg_str = "#{msg}\n#{trace}"
108
- else
109
- msg_str = msg.join(", ")
110
- end
111
- case
112
- when status < 500
113
- @logger.warn "Error: #{msg_str}"
114
- else
115
- @logger.error "Error: #{msg_str}"
116
- end
110
+ @rescue_exception = Proc.new {|env, e|
117
111
 
118
- response_body = {:errors => msg}.to_json
112
+ rescue_error = Proc.new {|status, exception, request_info, *msg|
113
+ if !msg || msg.empty?
114
+ trace = exception.backtrace.join("\n")
115
+ msg = "#{exception.class} - #{exception.message}"
116
+ msg_str = "#{msg}\n#{trace}"
117
+ else
118
+ msg_str = msg.join(", ")
119
+ end
120
+ case
121
+ when status < 500
122
+ @logger.warn "Error: #{msg_str}"
123
+ else
124
+ @logger.error "Error: #{msg_str}"
125
+ end
119
126
 
120
- query_string = (request_info[:query_string].respond_to?(:length) &&
121
- request_info[:query_string].length > 0) ? "?#{request_info[:query_string]}" : ""
122
- if @logger.debug?
123
- @logger.debug("Returning #{status} for #{request_info[:request_method]} " +
124
- "#{request_info[:path_info]}#{query_string}, body: #{response_body}")
125
- elsif @logger.info?
126
- @logger.info("Returning #{status} for #{request_info[:request_method]} " +
127
- "#{request_info[:path_info]}#{query_string}")
128
- end
127
+ response_body = Flapjack.dump_json(:errors => msg)
129
128
 
130
- [status, {}, response_body]
131
- }
129
+ query_string = (request_info[:query_string].respond_to?(:length) &&
130
+ request_info[:query_string].length > 0) ? "?#{request_info[:query_string]}" : ""
131
+ if @logger.debug?
132
+ @logger.debug("Returning #{status} for #{request_info[:request_method]} " +
133
+ "#{request_info[:path_info]}#{query_string}, body: #{response_body}")
134
+ elsif @logger.info?
135
+ @logger.info("Returning #{status} for #{request_info[:request_method]} " +
136
+ "#{request_info[:path_info]}#{query_string}")
137
+ end
138
+
139
+ headers = if 'DELETE'.eql?(request_info[:request_method])
140
+ # not set by default for delete, but the error structure is JSON
141
+ {'Content-Type' => JSONAPI_MEDIA_TYPE}
142
+ else
143
+ {}
144
+ end
145
+
146
+ [status, headers, response_body]
147
+ }
132
148
 
133
- rescue_exception = Proc.new {|env, e|
134
149
  request_info = {
135
150
  :path_info => env['REQUEST_PATH'],
136
151
  :request_method => env['REQUEST_METHOD'],
@@ -147,15 +162,21 @@ module Flapjack
147
162
  rescue_error.call(404, e, request_info, "could not find notification rules '" + e.notification_rule_ids.join(', ') + "'")
148
163
  when Flapjack::Gateways::JSONAPI::EntityNotFound
149
164
  rescue_error.call(404, e, request_info, "could not find entity '#{e.entity}'")
165
+ when Flapjack::Gateways::JSONAPI::EntitiesNotFound
166
+ entity_ids = "'" + e.entity_ids.join("', '") + "'"
167
+ rescue_error.call(404, e, request_info, "could not find entities: #{entity_ids}")
150
168
  when Flapjack::Gateways::JSONAPI::EntityCheckNotFound
151
169
  rescue_error.call(404, e, request_info, "could not find entity check '#{e.check}'")
170
+ when Flapjack::Gateways::JSONAPI::EntityChecksNotFound
171
+ checks = "'" + e.entity_checks.join("', '") + "'"
172
+ rescue_error.call(404, e, request_info, "could not find entity checks: #{checks}")
152
173
  when Flapjack::Gateways::JSONAPI::ResourceLocked
153
174
  rescue_error.call(423, e, request_info, "unable to obtain lock for resource '#{e.resource}'")
154
175
  else
155
176
  rescue_error.call(500, e, request_info)
156
177
  end
157
178
  }
158
- use ::Rack::FiberPool, :size => 25, :rescue_exception => rescue_exception
179
+ use ::Rack::FiberPool, :size => 25, :rescue_exception => @rescue_exception
159
180
 
160
181
  use ::Rack::MethodOverride
161
182
  use Flapjack::Gateways::JSONAPI::Rack::JsonParamsParser
@@ -205,7 +226,7 @@ module Flapjack
205
226
  before do
206
227
  input = nil
207
228
  query_string = (request.query_string.respond_to?(:length) &&
208
- request.query_string.length > 0) ? "?#{request.query_string}" : ""
229
+ (request.query_string.length > 0)) ? "?#{request.query_string}" : ""
209
230
  if logger.debug?
210
231
  input = env['rack.input'].read
211
232
  logger.debug("#{request.request_method} #{request.path_info}#{query_string} #{input}")
@@ -256,7 +277,7 @@ module Flapjack
256
277
  def err(status, *msg)
257
278
  msg_str = msg.join(", ")
258
279
  logger.info "Error: #{msg_str}"
259
- [status, {}, {:errors => msg}.to_json]
280
+ [status, {}, Flapjack.dump_json(:errors => msg)]
260
281
  end
261
282
 
262
283
  def is_json_request?
@@ -390,7 +411,7 @@ module Flapjack
390
411
  # bare 'params' may have splat/captures for regex route, see
391
412
  # https://github.com/sinatra/sinatra/issues/453
392
413
  post '*' do
393
- halt(405) unless request.params.empty? || is_json_request? || is_jsonapi_request
414
+ halt(405) unless request.params.empty? || is_json_request? || is_jsonapi_request?
394
415
  content_type JSONAPI_MEDIA_TYPE
395
416
  cors_headers
396
417
  pass
@@ -4,7 +4,6 @@ require 'socket'
4
4
  require 'eventmachine'
5
5
  require 'em-synchrony'
6
6
  require 'blather/client/client'
7
- require 'oj'
8
7
 
9
8
  require 'flapjack/utility'
10
9
 
@@ -210,9 +209,9 @@ module Flapjack
210
209
  end
211
210
 
212
211
  def send_pagerduty_event(event)
213
- options = { :body => Oj.dump(event) }
212
+ options = { :body => Flapjack.dump_json(event) }
214
213
  http = EM::HttpRequest.new(@pagerduty_events_api_url).post(options)
215
- response = Oj.load(http.response)
214
+ response = Flapjack.load_json(http.response)
216
215
  status = http.response_header.status
217
216
  @logger.debug "send_pagerduty_event got a return code of #{status.to_s} - #{response.inspect}"
218
217
  [status, response]
@@ -4,8 +4,6 @@ require 'em-hiredis'
4
4
  require 'em-synchrony'
5
5
  require 'em-synchrony/em-http'
6
6
 
7
- require 'oj'
8
-
9
7
  require 'flapjack/data/entity_check'
10
8
  require 'flapjack/data/alert'
11
9
  require 'flapjack/redis_pool'
@@ -40,7 +38,7 @@ module Flapjack
40
38
  redis_uri = @redis_config[:path] ||
41
39
  "redis://#{@redis_config[:host] || '127.0.0.1'}:#{@redis_config[:port] || '6379'}/#{@redis_config[:db] || '0'}"
42
40
  shutdown_redis = EM::Hiredis.connect(redis_uri)
43
- shutdown_redis.rpush(@config['queue'], Oj.dump('notification_type' => 'shutdown'))
41
+ shutdown_redis.rpush(@config['queue'], Flapjack.dump_json('notification_type' => 'shutdown'))
44
42
  end
45
43
 
46
44
  def start
@@ -67,7 +65,7 @@ module Flapjack
67
65
  event_json = events[queue][1]
68
66
 
69
67
  begin
70
- event = Oj.load(event_json)
68
+ event = Flapjack.load_json(event_json)
71
69
  @logger.debug("pagerduty notification event received: " + event.inspect)
72
70
 
73
71
  if 'shutdown'.eql?(event['notification_type'])
@@ -110,10 +108,13 @@ module Flapjack
110
108
  'trigger'
111
109
  end
112
110
 
111
+ # Setting the HOSTNAME and the SERVICE makes them visible in the Pagerduty UI
113
112
  pagerduty_event = { 'service_key' => alert.address,
114
113
  'incident_key' => alert.event_id,
115
114
  'event_type' => pagerduty_type,
116
- 'description' => message }
115
+ 'description' => message,
116
+ 'details' => {'HOSTNAME' => alert.entity,
117
+ 'SERVICE' => alert.check}}
117
118
 
118
119
  send_pagerduty_event(pagerduty_event)
119
120
  alert.record_send_success!
@@ -163,9 +164,9 @@ module Flapjack
163
164
  end
164
165
 
165
166
  def send_pagerduty_event(event)
166
- options = { :body => Oj.dump(event) }
167
+ options = { :body => Flapjack.dump_json(event) }
167
168
  http = EM::HttpRequest.new(PAGERDUTY_EVENTS_API_URL).post(options)
168
- response = Oj.load(http.response)
169
+ response = Flapjack.load_json(http.response)
169
170
  status = http.response_header.status
170
171
  @logger.debug "send_pagerduty_event got a return code of #{status.to_s} - #{response.inspect}"
171
172
  unless status == 200
@@ -260,7 +261,7 @@ module Flapjack
260
261
 
261
262
  http = EM::HttpRequest.new(url).get(options)
262
263
  begin
263
- response = Oj.load(http.response)
264
+ response = Flapjack.load_json(http.response)
264
265
  rescue Oj::Error
265
266
  @logger.error("failed to parse json from a post to #{url} ... response headers and body follows...")
266
267
  return nil
@@ -46,6 +46,25 @@ toolbox.batchRequest = function(klass, ids, amount, success) {
46
46
 
47
47
  Backbone.JSONAPIModel = Backbone.Model.extend({
48
48
 
49
+ initialize: function() {
50
+ var _persisted;
51
+
52
+ this.isPersisted = function () {
53
+ if ( !_.isUndefined(_persisted) && !_.isNull(_persisted) ) {
54
+ return(_persisted);
55
+ } else {
56
+ return(!_.isNull(this.id));
57
+ }
58
+ };
59
+ this.setPersisted = function(pers) {
60
+ _persisted = pers;
61
+ };
62
+ },
63
+
64
+ isNew: function() {
65
+ return(!this.isPersisted());
66
+ },
67
+
49
68
  // the following two methods, and batchRequest, should be folded into
50
69
  // Collection.fetch (and Model.fetch?)
51
70
  resolveLink: function(name, klass, superset) {
@@ -44,7 +44,11 @@ $(document).ready(function() {
44
44
  // skip if modal showing
45
45
  if ( $('#contactModal').hasClass('in') ) { return; }
46
46
 
47
- var contactDetailsView = new (Contact.Views.ContactDetails)({model: new (Contact.Model)()});
47
+ var contact = new (Contact.Model)();
48
+ contact.setPersisted(false);
49
+ contact.set('id', toolbox.generateUUID());
50
+
51
+ var contactDetailsView = new (Contact.Views.ContactDetails)({model: contact});
48
52
  contactDetailsView.render();
49
53
 
50
54
  $('div.modal-dialog').append(contactDetailsView.$el);
@@ -75,4 +79,4 @@ $(document).ready(function() {
75
79
  }
76
80
  });
77
81
 
78
- });
82
+ });
@@ -17,6 +17,7 @@
17
17
  links: {},
18
18
  },
19
19
  initialize: function(){
20
+ Backbone.JSONAPIModel.prototype.initialize.apply(this, arguments);
20
21
  this.on('change', this.setDirty, this);
21
22
  },
22
23
  toJSON: function() {
@@ -65,17 +66,7 @@
65
66
 
66
67
  this.collection.each(function(contact) {
67
68
  var item = new (Contact.Views.ListItem)({ model: contact });
68
- var itemEl = item.render().$el;
69
-
70
- itemEl.on('mouseenter', function(e) {
71
- e.stopPropagation();
72
- $(this).find('td.actions button').css('visibility', 'visible');
73
- }).on('mouseleave', function(e) {
74
- e.stopPropagation();
75
- $(this).find('td.actions button').css('visibility', 'hidden');
76
- });
77
-
78
- jqel.append(itemEl);
69
+ jqel.append(item.render().$el);
79
70
  });
80
71
 
81
72
  return this;
@@ -122,7 +113,7 @@
122
113
 
123
114
  var context = this;
124
115
 
125
- var deferreds = this.model.resolveLinks({media: Medium.List});
116
+ var deferreds = this.model.resolveLinks({media: Medium.List});
126
117
 
127
118
  $.when.apply($, deferreds).done(
128
119
  function() {
@@ -214,6 +205,7 @@
214
205
 
215
206
  if ( this.model.isNew() ) {
216
207
  var save_success = function(model, response, options) {
208
+ model.setPersisted(true);
217
209
  flapjack.contactList.add(model);
218
210
  $('#contactModal').modal('hide');
219
211
  };
@@ -297,8 +289,10 @@
297
289
  type: type,
298
290
  address: '',
299
291
  interval: 15,
300
- rollup_threshold: 3,
292
+ rollup_threshold: 3
301
293
  });
294
+ medium.setPersisted(false);
295
+ medium.set('id', options.contact.get('id') + '_' + type);
302
296
  context.collection.add(medium);
303
297
  }
304
298
  medium.contact = options.contact;
@@ -365,7 +359,8 @@
365
359
  var attrs = _.pick(model.attributes, changedAttrKeys);
366
360
  if ( model.isNew() ) {
367
361
  model.save(attrs);
368
- model.set('id', model.contact.get('id') + '_' + model.get('type'));
362
+ model.setPersisted(true);
363
+ model.contact.addLinked('contacts', 'media', model);
369
364
  } else {
370
365
  model.patch('media', attrs);
371
366
  }
@@ -6,6 +6,7 @@
6
6
  Medium.Model = Backbone.JSONAPIModel.extend({
7
7
  name: 'media',
8
8
  initialize: function(){
9
+ Backbone.JSONAPIModel.prototype.initialize.apply(this, arguments);
9
10
  this.on('change', this.setDirty, this);
10
11
  },
11
12
  defaults: {
@@ -66,7 +66,7 @@ $(document).ready(function() {
66
66
  var d = new Date().getTime();
67
67
  var value = {x: d, y: json.event_queue_length}
68
68
  data[0].values.push(value);
69
- console.log(data[0].values.length);
69
+ // console.log(data[0].values.length);
70
70
 
71
71
  // Remove old data, to keep the graph performant
72
72
  if (data[0].values.length > 100) {
@@ -20,13 +20,13 @@
20
20
  <td><@- first_name @></td>
21
21
  <td><@- last_name @></td>
22
22
  <td class="actions">
23
- <button type="button" class="btn btn-default contact-media" style="visibility: hidden" aria-hidden="true">Media</button>
23
+ <button type="button" class="btn btn-default contact-media" aria-hidden="true">Media</button>
24
24
  </td>
25
25
  <td class="actions">
26
- <button type="button" class="btn btn-default contact-entities" style="visibility: hidden" aria-hidden="true">Entities</button>
26
+ <button type="button" class="btn btn-default contact-entities" aria-hidden="true">Entities</button>
27
27
  </td>
28
28
  <td class="actions">
29
- <button type="button" class="btn btn-danger delete-contact" style="visibility: hidden" aria-hidden="true">&minus;</button>
29
+ <button type="button" class="btn btn-danger delete-contact">Delete</button>
30
30
  </td>
31
31
  </script>
32
32