flapjack 1.1.0 → 1.2.0rc1
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.
- 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
|
|