flapjack 1.1.0 → 1.2.0rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.ruby-version +1 -1
- data/.travis.yml +12 -7
- data/CHANGELOG.md +12 -0
- data/Gemfile +6 -2
- data/Gemfile-ruby1.9 +29 -0
- data/Gemfile-ruby1.9.lock +251 -0
- data/README.md +2 -2
- data/Rakefile +1 -0
- data/etc/flapjack_config.yaml.example +2 -2
- data/features/steps/events_steps.rb +2 -2
- data/features/steps/flapjack-netsaint-parser_steps.rb +1 -1
- data/features/support/env.rb +1 -6
- data/lib/flapjack/cli/import.rb +2 -5
- data/lib/flapjack/cli/purge.rb +4 -4
- data/lib/flapjack/cli/receiver.rb +122 -54
- data/lib/flapjack/cli/server.rb +0 -5
- data/lib/flapjack/coordinator.rb +6 -0
- data/lib/flapjack/data/contact.rb +10 -62
- data/lib/flapjack/data/entity.rb +36 -52
- data/lib/flapjack/data/entity_check.rb +90 -21
- data/lib/flapjack/data/event.rb +4 -5
- data/lib/flapjack/data/notification.rb +8 -10
- data/lib/flapjack/data/notification_rule.rb +32 -35
- data/lib/flapjack/data/tagged.rb +48 -0
- data/lib/flapjack/gateways/jabber.rb +4 -5
- data/lib/flapjack/gateways/jsonapi/check_methods.rb +45 -7
- data/lib/flapjack/gateways/jsonapi/check_presenter.rb +1 -1
- data/lib/flapjack/gateways/jsonapi/contact_methods.rb +8 -2
- data/lib/flapjack/gateways/jsonapi/entity_methods.rb +26 -8
- data/lib/flapjack/gateways/jsonapi/medium_methods.rb +13 -9
- data/lib/flapjack/gateways/jsonapi/metrics_methods.rb +2 -2
- data/lib/flapjack/gateways/jsonapi/notification_rule_methods.rb +1 -1
- data/lib/flapjack/gateways/jsonapi/pagerduty_credential_methods.rb +24 -17
- data/lib/flapjack/gateways/jsonapi/rack/json_params_parser.rb +1 -1
- data/lib/flapjack/gateways/jsonapi/report_methods.rb +4 -4
- data/lib/flapjack/gateways/jsonapi.rb +52 -31
- data/lib/flapjack/gateways/oobetet.rb +2 -3
- data/lib/flapjack/gateways/pagerduty.rb +9 -8
- data/lib/flapjack/gateways/web/public/js/backbone.jsonapi.js +19 -0
- data/lib/flapjack/gateways/web/public/js/flapjack.js +6 -2
- data/lib/flapjack/gateways/web/public/js/modules/contact.js +9 -14
- data/lib/flapjack/gateways/web/public/js/modules/medium.js +1 -0
- data/lib/flapjack/gateways/web/public/js/self_stats.js +1 -1
- data/lib/flapjack/gateways/web/views/edit_contacts.html.erb +3 -3
- data/lib/flapjack/gateways/web.rb +8 -7
- data/lib/flapjack/notifier.rb +2 -4
- data/lib/flapjack/processor.rb +2 -2
- data/lib/flapjack/version.rb +1 -1
- data/lib/flapjack.rb +10 -0
- data/spec/lib/flapjack/coordinator_spec.rb +18 -0
- data/spec/lib/flapjack/data/contact_spec.rb +4 -12
- data/spec/lib/flapjack/data/entity_check_spec.rb +56 -3
- data/spec/lib/flapjack/data/entity_spec.rb +79 -67
- data/spec/lib/flapjack/data/event_spec.rb +78 -78
- data/spec/lib/flapjack/data/notification_rule_spec.rb +4 -2
- data/spec/lib/flapjack/gateways/jsonapi/check_methods_spec.rb +94 -11
- data/spec/lib/flapjack/gateways/jsonapi/entity_methods_spec.rb +84 -0
- data/spec/lib/flapjack/gateways/pagerduty_spec.rb +5 -3
- data/spec/lib/flapjack/gateways/web_spec.rb +3 -3
- data/spec/service_consumers/pact_helper.rb +74 -0
- data/spec/service_consumers/pacts/flapjack-diner_v1.0.json +4522 -0
- data/spec/service_consumers/provider_states_for_flapjack-diner.rb +356 -0
- data/spec/spec_helper.rb +0 -8
- data/spec/support/jsonapi_helper.rb +1 -1
- data/tasks/benchmarks.rake +6 -3
- data/tasks/profile.rake +1 -1
- data/tmp/acknowledge.rb +0 -3
- data/tmp/create_event_ok.rb +0 -3
- data/tmp/create_event_unknown.rb +0 -3
- data/tmp/create_events_failure.rb +0 -3
- data/tmp/create_events_ok.rb +0 -3
- data/tmp/create_events_ok_fail_ack_ok.rb +0 -3
- data/tmp/create_events_ok_failure.rb +2 -5
- data/tmp/create_events_ok_failure_ack.rb +0 -3
- data/tmp/test_json_post.rb +4 -3
- data/tmp/test_notification_rules_api.rb +2 -3
- metadata +13 -8
- data/lib/flapjack/data/tag.rb +0 -61
- data/lib/flapjack/data/tag_set.rb +0 -16
- 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
|
-
|
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
|
-
|
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
|
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
|
100
|
-
|
101
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
69
|
-
|
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
|
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 =>
|
123
|
-
:rollup_threshold =>
|
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
|
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.
|
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
|
-
|
91
|
+
Flapjack.dump_json(metrics)
|
92
92
|
end
|
93
93
|
end
|
94
94
|
|
@@ -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]
|
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
|
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
|
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
|
95
|
+
pdc = contact.pagerduty_credentials
|
96
|
+
pd_data = pdc.nil? ? {} : pdc.clone
|
92
97
|
|
93
98
|
case property
|
94
99
|
when 'service_key'
|
95
|
-
|
96
|
-
contact.set_pagerduty_credentials(
|
100
|
+
pd_data['service_key'] = value
|
101
|
+
contact.set_pagerduty_credentials(pd_data)
|
97
102
|
when 'subdomain'
|
98
|
-
|
99
|
-
contact.set_pagerduty_credentials(
|
103
|
+
pd_data['subdomain'] = value
|
104
|
+
contact.set_pagerduty_credentials(pd_data)
|
100
105
|
when 'username'
|
101
|
-
|
102
|
-
contact.set_pagerduty_credentials(
|
106
|
+
pd_data['username'] = value
|
107
|
+
contact.set_pagerduty_credentials(pd_data)
|
103
108
|
when 'password'
|
104
|
-
|
105
|
-
contact.set_pagerduty_credentials(
|
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|
|
120
|
+
params[:contact_id].split(',').uniq.collect {|c_id|
|
121
|
+
find_contact(c_id)
|
122
|
+
}.each {|contact|
|
116
123
|
contact.delete_pagerduty_credentials
|
117
|
-
|
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? ? {} :
|
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.
|
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
|
125
|
-
"\"linked\":{\"entities\":" + entity_data
|
126
|
-
"\"checks\":" + check_data
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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, {},
|
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 =>
|
212
|
+
options = { :body => Flapjack.dump_json(event) }
|
214
213
|
http = EM::HttpRequest.new(@pagerduty_events_api_url).post(options)
|
215
|
-
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'],
|
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 =
|
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 =>
|
167
|
+
options = { :body => Flapjack.dump_json(event) }
|
167
168
|
http = EM::HttpRequest.new(PAGERDUTY_EVENTS_API_URL).post(options)
|
168
|
-
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 =
|
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
|
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
|
-
|
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:
|
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.
|
362
|
+
model.setPersisted(true);
|
363
|
+
model.contact.addLinked('contacts', 'media', model);
|
369
364
|
} else {
|
370
365
|
model.patch('media', attrs);
|
371
366
|
}
|
@@ -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"
|
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"
|
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"
|
29
|
+
<button type="button" class="btn btn-danger delete-contact">Delete</button>
|
30
30
|
</td>
|
31
31
|
</script>
|
32
32
|
|