sensu 0.17.0.beta → 0.17.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -1
- data/bin/sensu-api +4 -4
- data/bin/sensu-client +4 -4
- data/bin/sensu-server +4 -4
- data/lib/sensu/api/process.rb +704 -0
- data/lib/sensu/cli.rb +21 -15
- data/lib/sensu/client/process.rb +414 -0
- data/lib/sensu/client/socket.rb +226 -0
- data/lib/sensu/constants.rb +4 -1
- data/lib/sensu/daemon.rb +125 -73
- data/lib/sensu/redis.rb +10 -5
- data/lib/sensu/server/filter.rb +309 -0
- data/lib/sensu/server/handle.rb +168 -0
- data/lib/sensu/server/mutate.rb +92 -0
- data/lib/sensu/server/process.rb +811 -0
- data/lib/sensu/server/sandbox.rb +21 -0
- data/lib/sensu/server/socket.rb +42 -0
- data/lib/sensu/utilities.rb +29 -3
- data/sensu.gemspec +29 -28
- metadata +30 -12
- data/lib/sensu/api.rb +0 -704
- data/lib/sensu/client.rb +0 -298
- data/lib/sensu/sandbox.rb +0 -11
- data/lib/sensu/server.rb +0 -772
- data/lib/sensu/socket.rb +0 -246
@@ -0,0 +1,309 @@
|
|
1
|
+
require "sensu/server/sandbox"
|
2
|
+
|
3
|
+
module Sensu
|
4
|
+
module Server
|
5
|
+
module Filter
|
6
|
+
# Determine if a period of time (window) is subdued. The
|
7
|
+
# provided condition must have a `:begin` and `:end` time, eg.
|
8
|
+
# "11:30:00 PM", or `false` will be returned.
|
9
|
+
#
|
10
|
+
# @param condition [Hash]
|
11
|
+
# @option condition [String] :begin time.
|
12
|
+
# @option condition [String] :end time.
|
13
|
+
# @return [TrueClass, FalseClass]
|
14
|
+
def subdue_time?(condition)
|
15
|
+
if condition.has_key?(:begin) && condition.has_key?(:end)
|
16
|
+
begin_time = Time.parse(condition[:begin])
|
17
|
+
end_time = Time.parse(condition[:end])
|
18
|
+
if end_time < begin_time
|
19
|
+
if Time.now < end_time
|
20
|
+
begin_time = Time.parse("12:00:00 AM")
|
21
|
+
else
|
22
|
+
end_time = Time.parse("11:59:59 PM")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
Time.now >= begin_time && Time.now <= end_time
|
26
|
+
else
|
27
|
+
false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Determine if the current day is subdued. The provided
|
32
|
+
# condition must have a list of `:days`, or false will be
|
33
|
+
# returned.
|
34
|
+
#
|
35
|
+
# @param condition [Hash]
|
36
|
+
# @option condition [Array] :days of the week to subdue.
|
37
|
+
# @return [TrueClass, FalseClass]
|
38
|
+
def subdue_days?(condition)
|
39
|
+
if condition.has_key?(:days)
|
40
|
+
days = condition[:days].map(&:downcase)
|
41
|
+
days.include?(Time.now.strftime("%A").downcase)
|
42
|
+
else
|
43
|
+
false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Determine if there is an exception a period of time (window)
|
48
|
+
# that is subdued. The provided condition must have an
|
49
|
+
# `:exception`, containing one or more `:begin` and `:end`
|
50
|
+
# times, eg. "11:30:00 PM", or `false` will be returned. If
|
51
|
+
# there are any exceptions to a subdued period of time, `true`
|
52
|
+
# will be returned.
|
53
|
+
#
|
54
|
+
# @param condition [Hash]
|
55
|
+
# @option condition [Hash] :exceptions array of `:begin` and
|
56
|
+
# `:end` times.
|
57
|
+
# @return [TrueClass, FalseClass]
|
58
|
+
def subdue_exception?(condition)
|
59
|
+
if condition.has_key?(:exceptions)
|
60
|
+
condition[:exceptions].any? do |exception|
|
61
|
+
Time.now >= Time.parse(exception[:begin]) && Time.now <= Time.parse(exception[:end])
|
62
|
+
end
|
63
|
+
else
|
64
|
+
false
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Determine if an action is subdued and if there is an
|
69
|
+
# exception. This method makes use of `subdue_time?()`,
|
70
|
+
# `subdue_days?()`, and subdue_exception?().
|
71
|
+
#
|
72
|
+
# @param condition [Hash]
|
73
|
+
# @return [TrueClass, FalseClass]
|
74
|
+
def action_subdued?(condition)
|
75
|
+
subdued = subdue_time?(condition) || subdue_days?(condition)
|
76
|
+
subdued && !subdue_exception?(condition)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Determine if an event handler is subdued, by conditions set in
|
80
|
+
# the check and/or the handler definition. If any of the
|
81
|
+
# conditions are true, without an exception, the handler is
|
82
|
+
# subdued.
|
83
|
+
#
|
84
|
+
# @param handler [Hash] definition.
|
85
|
+
# @param event [Hash] data possibly containing subdue
|
86
|
+
# conditions.
|
87
|
+
# @return [TrueClass, FalseClass]
|
88
|
+
def handler_subdued?(handler, event)
|
89
|
+
subdued = []
|
90
|
+
if handler[:subdue]
|
91
|
+
subdued << action_subdued?(handler[:subdue])
|
92
|
+
end
|
93
|
+
check = event[:check]
|
94
|
+
if check[:subdue] && check[:subdue][:at] != "publisher"
|
95
|
+
subdued << action_subdued?(check[:subdue])
|
96
|
+
end
|
97
|
+
subdued.any?
|
98
|
+
end
|
99
|
+
|
100
|
+
# Determine if a check request is subdued, by conditions set in
|
101
|
+
# the check definition. If any of the conditions are true,
|
102
|
+
# without an exception, the check request is subdued.
|
103
|
+
#
|
104
|
+
# @param check [Hash] definition.
|
105
|
+
# @return [TrueClass, FalseClass]
|
106
|
+
def check_request_subdued?(check)
|
107
|
+
if check[:subdue] && check[:subdue][:at] == "publisher"
|
108
|
+
action_subdued?(check[:subdue])
|
109
|
+
else
|
110
|
+
false
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Determine if handling is disabled for an event. Check
|
115
|
+
# definitions can disable event handling with an attribute,
|
116
|
+
# `:handle`, by setting it to `false`.
|
117
|
+
#
|
118
|
+
# @param event [Hash]
|
119
|
+
# @return [TrueClass, FalseClass]
|
120
|
+
def handling_disabled?(event)
|
121
|
+
event[:check][:handle] == false
|
122
|
+
end
|
123
|
+
|
124
|
+
# Determine if an event with an action should be handled. An
|
125
|
+
# event action of `:flapping` indicates that the event state is
|
126
|
+
# flapping, and the event should not be handled unless its
|
127
|
+
# handler has `:handle_flapping` set to `true`.
|
128
|
+
#
|
129
|
+
# @param handler [Hash] definition.
|
130
|
+
# @param event [Hash]
|
131
|
+
# @return [TrueClass, FalseClass]
|
132
|
+
def handle_action?(handler, event)
|
133
|
+
event[:action] != :flapping ||
|
134
|
+
(event[:action] == :flapping && !!handler[:handle_flapping])
|
135
|
+
end
|
136
|
+
|
137
|
+
# Determine if an event with a check severity will be handled.
|
138
|
+
# Event handlers can specify the check severities they will
|
139
|
+
# handle, using the definition attribute `:severities`. The
|
140
|
+
# possible severities are "ok", "warning", "critical", and
|
141
|
+
# "unknown". Handler severity filtering is bypassed when the
|
142
|
+
# event `:action` is `:resolve`, if the check history contains
|
143
|
+
# one of the specified severities since the last OK result.
|
144
|
+
#
|
145
|
+
# @param handler [Hash] definition.
|
146
|
+
# @param event [Hash]
|
147
|
+
# @return [TrueClass, FalseClass]
|
148
|
+
def handle_severity?(handler, event)
|
149
|
+
if handler.has_key?(:severities)
|
150
|
+
case event[:action]
|
151
|
+
when :resolve
|
152
|
+
event[:check][:history].reverse[1..-1].any? do |status|
|
153
|
+
if status.to_i == 0
|
154
|
+
break false
|
155
|
+
end
|
156
|
+
severity = SEVERITIES[status.to_i] || "unknown"
|
157
|
+
handler[:severities].include?(severity)
|
158
|
+
end
|
159
|
+
else
|
160
|
+
severity = SEVERITIES[event[:check][:status]] || "unknown"
|
161
|
+
handler[:severities].include?(severity)
|
162
|
+
end
|
163
|
+
else
|
164
|
+
true
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
# Ruby eval() a string containing an expression, within the
|
169
|
+
# scope/context of a sandbox. This method is for filter
|
170
|
+
# attribute values starting with "eval:", with the Ruby
|
171
|
+
# expression following the colon. A single variable is provided
|
172
|
+
# to the expression, `value`, equal to the corresponding event
|
173
|
+
# attribute value. The expression is expected to return a
|
174
|
+
# boolean value.
|
175
|
+
#
|
176
|
+
# @param raw_eval_string [String] containing the Ruby
|
177
|
+
# expression to be evaluated.
|
178
|
+
# @param value [Object] of the corresponding event attribute.
|
179
|
+
# @return [TrueClass, FalseClass]
|
180
|
+
def eval_attribute_value(raw_eval_string, value)
|
181
|
+
begin
|
182
|
+
eval_string = raw_eval_string.gsub(/^eval:(\s+)?/, "")
|
183
|
+
!!Sandbox.eval(eval_string, value)
|
184
|
+
rescue => error
|
185
|
+
@logger.error("filter attribute eval error", {
|
186
|
+
:raw_eval_string => raw_eval_string,
|
187
|
+
:value => value,
|
188
|
+
:error => error.to_s
|
189
|
+
})
|
190
|
+
false
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# Determine if all filter attribute values match those of the
|
195
|
+
# corresponding event attributes. Attributes match if the value
|
196
|
+
# objects are equivalent, are both hashes with matching
|
197
|
+
# key/value pairs (recursive), have equal string values, or
|
198
|
+
# evaluate to true (Ruby eval).
|
199
|
+
#
|
200
|
+
# @param hash_one [Hash]
|
201
|
+
# @param hash_two [Hash]
|
202
|
+
# @return [TrueClass, FalseClass]
|
203
|
+
def filter_attributes_match?(hash_one, hash_two)
|
204
|
+
hash_one.all? do |key, value_one|
|
205
|
+
value_two = hash_two[key]
|
206
|
+
case
|
207
|
+
when value_one == value_two
|
208
|
+
true
|
209
|
+
when value_one.is_a?(Hash) && value_two.is_a?(Hash)
|
210
|
+
filter_attributes_match?(value_one, value_two)
|
211
|
+
when hash_one[key].to_s == hash_two[key].to_s
|
212
|
+
true
|
213
|
+
when value_one.is_a?(String) && value_one.start_with?("eval:")
|
214
|
+
eval_attribute_value(value_one, value_two)
|
215
|
+
else
|
216
|
+
false
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# Determine if an event is filtered by an event filter, standard
|
222
|
+
# or extension. This method first checks for the existence of a
|
223
|
+
# standard filter, then checks for an extension if a standard
|
224
|
+
# filter is not defined. The provided callback is called with a
|
225
|
+
# single parameter, indicating if the event was filtered by a
|
226
|
+
# filter. If a filter does not exist for the provided name, the
|
227
|
+
# event is not filtered.
|
228
|
+
#
|
229
|
+
# @param filter_name [String]
|
230
|
+
# @param event [Hash]
|
231
|
+
# @param callback [Proc]
|
232
|
+
def event_filter(filter_name, event, &callback)
|
233
|
+
case
|
234
|
+
when @settings.filter_exists?(filter_name)
|
235
|
+
filter = @settings[:filters][filter_name]
|
236
|
+
matched = filter_attributes_match?(filter[:attributes], event)
|
237
|
+
callback.call(filter[:negate] ? matched : !matched)
|
238
|
+
when @extensions.filter_exists?(filter_name)
|
239
|
+
extension = @extensions[:filters][filter_name]
|
240
|
+
extension.safe_run(event) do |output, status|
|
241
|
+
callback.call(status == 0)
|
242
|
+
end
|
243
|
+
else
|
244
|
+
@logger.error("unknown filter", :filter_name => filter_name)
|
245
|
+
callback.call(false)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
# Determine if an event is filtered for a handler. If a handler
|
250
|
+
# specifies one or more filters, via `:filters` or `:filter`,
|
251
|
+
# the `event_filter()` method is called for each of them. If any
|
252
|
+
# of the filters return `true`, the event is filtered for the
|
253
|
+
# handler. If no filters are defined in the handler definition,
|
254
|
+
# the event is not filtered.
|
255
|
+
#
|
256
|
+
# @param handler [Hash] definition.
|
257
|
+
# @param event [Hash]
|
258
|
+
# @param callback [Proc]
|
259
|
+
def event_filtered?(handler, event, &callback)
|
260
|
+
if handler.has_key?(:filters) || handler.has_key?(:filter)
|
261
|
+
filter_list = Array(handler[:filters] || handler[:filter])
|
262
|
+
filter_results = EM::Iterator.new(filter_list)
|
263
|
+
run_filters = Proc.new do |filter_name, iterator|
|
264
|
+
event_filter(filter_name, event) do |filtered|
|
265
|
+
iterator.return(filtered)
|
266
|
+
end
|
267
|
+
end
|
268
|
+
filtered = Proc.new do |results|
|
269
|
+
callback.call(results.any?)
|
270
|
+
end
|
271
|
+
filter_results.map(run_filters, filtered)
|
272
|
+
else
|
273
|
+
callback.call(false)
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
# Attempt to filter an event for a handler. This method will
|
278
|
+
# check to see if handling is disabled, if the event action is
|
279
|
+
# handled, if the event check severity is handled, if the
|
280
|
+
# handler is sbuded, and if the event is filtered by any of the
|
281
|
+
# filters specified in the handler definition.
|
282
|
+
#
|
283
|
+
# @param handler [Hash] definition.
|
284
|
+
# @param event [Hash]
|
285
|
+
# @param callback [Proc]
|
286
|
+
def filter_event(handler, event, &callback)
|
287
|
+
details = {:handler => handler, :event => event}
|
288
|
+
if handling_disabled?(event)
|
289
|
+
@logger.info("event handling disabled for event", details)
|
290
|
+
elsif !handle_action?(handler, event)
|
291
|
+
@logger.info("handler does not handle action", details)
|
292
|
+
elsif !handle_severity?(handler, event)
|
293
|
+
@logger.info("handler does not handle event severity", details)
|
294
|
+
elsif handler_subdued?(handler, event)
|
295
|
+
@logger.info("handler is subdued", details)
|
296
|
+
else
|
297
|
+
event_filtered?(handler, event) do |filtered|
|
298
|
+
unless filtered
|
299
|
+
callback.call(event)
|
300
|
+
else
|
301
|
+
@logger.info("event was filtered", details)
|
302
|
+
@handling_event_count -= 1 if @handling_event_count
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
require "sensu/server/socket"
|
2
|
+
|
3
|
+
module Sensu
|
4
|
+
module Server
|
5
|
+
module Handle
|
6
|
+
# Create a handler error callback, for logging the error and
|
7
|
+
# decrementing the `@handling_event_count` by `1`.
|
8
|
+
#
|
9
|
+
# @param handler [Object]
|
10
|
+
# @param event_data [Object]
|
11
|
+
# @return [Proc] error callback.
|
12
|
+
def handler_error(handler, event_data)
|
13
|
+
Proc.new do |error|
|
14
|
+
@logger.error("handler error", {
|
15
|
+
:handler => handler,
|
16
|
+
:event_data => event_data,
|
17
|
+
:error => error.to_s
|
18
|
+
})
|
19
|
+
@handling_event_count -= 1 if @handling_event_count
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Execute a pipe event handler, using the defined handler
|
24
|
+
# command to spawn a process, passing it event data via STDIN.
|
25
|
+
# Log the handler output lines and decrement the
|
26
|
+
# `@handling_event_count` by `1` when the handler executes
|
27
|
+
# successfully.
|
28
|
+
#
|
29
|
+
# @param handler [Hash] definition.
|
30
|
+
# @param event_data [Object] provided to the spawned handler
|
31
|
+
# process via STDIN.
|
32
|
+
def pipe_handler(handler, event_data)
|
33
|
+
options = {:data => event_data, :timeout => handler[:timeout]}
|
34
|
+
Spawn.process(handler[:command], options) do |output, status|
|
35
|
+
@logger.info("handler output", {
|
36
|
+
:handler => handler,
|
37
|
+
:output => output.lines
|
38
|
+
})
|
39
|
+
@handling_event_count -= 1 if @handling_event_count
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Connect to a TCP socket and transmit event data to it, then
|
44
|
+
# close the connection. The `Sensu::Server::Socket` connection
|
45
|
+
# handler is used for the socket. The socket timeouts are
|
46
|
+
# configurable via the handler definition, `:timeout`. The
|
47
|
+
# `handler_error()` method is used to create the `on_error`
|
48
|
+
# callback for the connection handler. The `on_error` callback
|
49
|
+
# is call in the event of any error(s). The
|
50
|
+
# `@handling_event_count` is decremented by `1` when the data is
|
51
|
+
# transmitted successfully, `on_success`.
|
52
|
+
#
|
53
|
+
# @param handler [Hash] definition.
|
54
|
+
# @param event_data [Object] to transmit to the TCP socket.
|
55
|
+
def tcp_handler(handler, event_data)
|
56
|
+
on_error = handler_error(handler, event_data)
|
57
|
+
begin
|
58
|
+
EM::connect(handler[:socket][:host], handler[:socket][:port], Socket) do |socket|
|
59
|
+
socket.on_success = Proc.new do
|
60
|
+
@handling_event_count -= 1 if @handling_event_count
|
61
|
+
end
|
62
|
+
socket.on_error = on_error
|
63
|
+
timeout = handler[:timeout] || 10
|
64
|
+
socket.pending_connect_timeout = timeout
|
65
|
+
socket.comm_inactivity_timeout = timeout
|
66
|
+
socket.send_data(event_data.to_s)
|
67
|
+
socket.close_connection_after_writing
|
68
|
+
end
|
69
|
+
rescue => error
|
70
|
+
on_error.call(error)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Transmit event data to a UDP socket, then close the
|
75
|
+
# connection. The `@handling_event_count` is decremented by `1`
|
76
|
+
# when the data is assumed to have been transmitted.
|
77
|
+
#
|
78
|
+
# @param handler [Hash] definition.
|
79
|
+
# @param event_data [Object] to transmit to the UDP socket.
|
80
|
+
def udp_handler(handler, event_data)
|
81
|
+
begin
|
82
|
+
EM::open_datagram_socket("0.0.0.0", 0, nil) do |socket|
|
83
|
+
socket.send_datagram(event_data.to_s, handler[:socket][:host], handler[:socket][:port])
|
84
|
+
socket.close_connection_after_writing
|
85
|
+
@handling_event_count -= 1 if @handling_event_count
|
86
|
+
end
|
87
|
+
rescue => error
|
88
|
+
handler_error(handler, event_data).call(error)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Publish event data to a Sensu transport pipe. Event data that
|
93
|
+
# is `nil` or empty will not be published, to prevent transport
|
94
|
+
# errors. The `@handling_event_count` is decremented by `1`,
|
95
|
+
# even if the event data is not published.
|
96
|
+
#
|
97
|
+
# @param handler [Hash] definition.
|
98
|
+
# @param event_data [Object] to publish to the transport pipe.
|
99
|
+
def transport_handler(handler, event_data)
|
100
|
+
unless event_data.nil? || event_data.empty?
|
101
|
+
pipe = handler[:pipe]
|
102
|
+
pipe_options = pipe[:options] || {}
|
103
|
+
@transport.publish(pipe[:type].to_sym, pipe[:name], event_data, pipe_options) do |info|
|
104
|
+
if info[:error]
|
105
|
+
handler_error(handler, event_data).call(info[:error])
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
@handling_event_count -= 1 if @handling_event_count
|
110
|
+
end
|
111
|
+
|
112
|
+
# Run a handler extension, within the Sensu EventMachine reactor
|
113
|
+
# (event loop). The extension API `safe_run()` method is used to
|
114
|
+
# guard against most errors. The `safe_run()` callback is always
|
115
|
+
# called, logging the extension run output and status, and
|
116
|
+
# decrementing the `@handling_event_count` by `1`.
|
117
|
+
#
|
118
|
+
# @param handler [Hash] definition.
|
119
|
+
# @param event_data [Object] to pass to the handler extension.
|
120
|
+
def handler_extension(handler, event_data)
|
121
|
+
handler.safe_run(event_data) do |output, status|
|
122
|
+
@logger.info("handler extension output", {
|
123
|
+
:extension => handler.definition,
|
124
|
+
:output => output,
|
125
|
+
:status => status
|
126
|
+
})
|
127
|
+
@handling_event_count -= 1 if @handling_event_count
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Route the event data to the appropriate handler type method.
|
132
|
+
# Routing is done using the handler definition, `:type`.
|
133
|
+
#
|
134
|
+
# @param handler [Hash] definition.
|
135
|
+
# @param event_data [Object] to pass to the handler type method.
|
136
|
+
def handler_type_router(handler, event_data)
|
137
|
+
case handler[:type]
|
138
|
+
when "pipe"
|
139
|
+
pipe_handler(handler, event_data)
|
140
|
+
when "tcp"
|
141
|
+
tcp_handler(handler, event_data)
|
142
|
+
when "udp"
|
143
|
+
udp_handler(handler, event_data)
|
144
|
+
when "transport"
|
145
|
+
transport_handler(handler, event_data)
|
146
|
+
when "extension"
|
147
|
+
handler_extension(handler, event_data)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# Handle an event, providing event data to an event handler.
|
152
|
+
# This method logs event data and the handler definition at the
|
153
|
+
# debug log level, then calls the `handler_type_router()`
|
154
|
+
# method.
|
155
|
+
#
|
156
|
+
# @param handler [Hash] definition.
|
157
|
+
# @param event_data [Object] to pass to an event handler.
|
158
|
+
def handle_event(handler, event_data)
|
159
|
+
definition = handler.is_a?(Hash) ? handler : handler.definition
|
160
|
+
@logger.debug("handling event", {
|
161
|
+
:event_data => event_data,
|
162
|
+
:handler => definition
|
163
|
+
})
|
164
|
+
handler_type_router(handler, event_data)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module Sensu
|
2
|
+
module Server
|
3
|
+
module Mutate
|
4
|
+
# Create a mutator callback (Proc). A mutator callback takes two
|
5
|
+
# parameters, for the mutator output and status code. The
|
6
|
+
# created callback can be used for standard mutators and mutator
|
7
|
+
# extensions. The provided callback will only be called when the
|
8
|
+
# mutator status is `0` (OK). If the status is not `0`, an error
|
9
|
+
# is logged, and the `@handling_event_count` is decremented by
|
10
|
+
# `1`.
|
11
|
+
#
|
12
|
+
# @param mutator [Object] definition or extension.
|
13
|
+
# @param event [Hash] data.
|
14
|
+
# @param callback [Proc] to call when the mutator status is `0`.
|
15
|
+
# @return [Proc] mutator callback.
|
16
|
+
def mutator_callback(mutator, event, &callback)
|
17
|
+
Proc.new do |output, status|
|
18
|
+
if status == 0
|
19
|
+
callback.call(output)
|
20
|
+
else
|
21
|
+
definition = mutator.is_a?(Hash) ? mutator : mutator.definition
|
22
|
+
@logger.error("mutator error", {
|
23
|
+
:mutator => definition,
|
24
|
+
:event => event,
|
25
|
+
:output => output,
|
26
|
+
:status => status
|
27
|
+
})
|
28
|
+
@handling_event_count -= 1 if @handling_event_count
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Execute a standard mutator (pipe), spawn a process using the
|
34
|
+
# mutator command and pipe the event data to it via STDIN. The
|
35
|
+
# `mutator_callback()` method is used to create the mutator
|
36
|
+
# callback, wrapping the provided callback (event handler).
|
37
|
+
#
|
38
|
+
# @param mutator [Hash] definition.
|
39
|
+
# @param event [Hash] data.
|
40
|
+
# @param callback [Proc] to call when the mutator executes
|
41
|
+
# successfully.
|
42
|
+
def pipe_mutator(mutator, event, &callback)
|
43
|
+
options = {:data => MultiJson.dump(event), :timeout => mutator[:timeout]}
|
44
|
+
block = mutator_callback(mutator, event, &callback)
|
45
|
+
Spawn.process(mutator[:command], options, &block)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Run a mutator extension, within the Sensu EventMachine reactor
|
49
|
+
# (event loop). The `mutator_callback()` method is used to
|
50
|
+
# create the mutator callback, wrapping the provided callback
|
51
|
+
# (event handler).
|
52
|
+
#
|
53
|
+
# @param mutator [Object] extension.
|
54
|
+
# @param event [Hash] data.
|
55
|
+
# @param callback [Proc] to call when the mutator runs
|
56
|
+
# successfully.
|
57
|
+
def mutator_extension(mutator, event, &callback)
|
58
|
+
block = mutator_callback(mutator, event, &callback)
|
59
|
+
mutator.safe_run(event, &block)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Mutate event data for a handler. By default, the "json"
|
63
|
+
# mutator is used, unless the handler specifies another mutator.
|
64
|
+
# If a mutator does not exist, not defined or a missing
|
65
|
+
# extension, an error will be logged and the
|
66
|
+
# `@handling_event_count` is decremented by `1`. This method
|
67
|
+
# first checks for the existence of a standard mutator, then
|
68
|
+
# checks for an extension if a standard mutator is not defined.
|
69
|
+
#
|
70
|
+
# @param handler [Hash] definition.
|
71
|
+
# @param event [Hash] data.
|
72
|
+
# @param callback [Proc] to call when the mutator executes/runs
|
73
|
+
# successfully (event handler).
|
74
|
+
def mutate_event(handler, event, &callback)
|
75
|
+
mutator_name = handler[:mutator] || "json"
|
76
|
+
case
|
77
|
+
when @settings.mutator_exists?(mutator_name)
|
78
|
+
mutator = @settings[:mutators][mutator_name]
|
79
|
+
pipe_mutator(mutator, event, &callback)
|
80
|
+
when @extensions.mutator_exists?(mutator_name)
|
81
|
+
mutator = @extensions[:mutators][mutator_name]
|
82
|
+
mutator_extension(mutator, event, &callback)
|
83
|
+
else
|
84
|
+
@logger.error("unknown mutator", {
|
85
|
+
:mutator_name => mutator_name
|
86
|
+
})
|
87
|
+
@handling_event_count -= 1 if @handling_event_count
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|