sensu 0.22.2-java → 0.23.0.beta-java

Sign up to get free protection for your applications and to get access to all the features.
data/lib/sensu/daemon.rb CHANGED
@@ -1,31 +1,30 @@
1
1
  require "rubygems"
2
2
 
3
- gem "multi_json", "1.11.2"
4
- gem "eventmachine", "1.0.9.1"
3
+ gem "eventmachine", "1.2.0.1"
5
4
 
6
- gem "sensu-logger", "1.1.0"
7
- gem "sensu-settings", "3.3.0"
5
+ gem "sensu-json", "1.1.0"
6
+ gem "sensu-logger", "1.2.0"
7
+ gem "sensu-settings", "3.4.0"
8
8
  gem "sensu-extension", "1.5.0"
9
- gem "sensu-extensions", "1.4.0"
10
- gem "sensu-transport", "4.0.0"
9
+ gem "sensu-extensions", "1.5.0"
10
+ gem "sensu-transport", "5.0.0"
11
11
  gem "sensu-spawn", "1.8.0"
12
+ gem "sensu-redis", "1.2.0"
12
13
 
13
14
  require "time"
14
15
  require "uri"
15
16
 
17
+ require "sensu/json"
16
18
  require "sensu/logger"
17
19
  require "sensu/settings"
18
20
  require "sensu/extensions"
19
21
  require "sensu/transport"
20
22
  require "sensu/spawn"
23
+ require "sensu/redis"
21
24
 
22
25
  require "sensu/constants"
23
26
  require "sensu/utilities"
24
27
  require "sensu/cli"
25
- require "sensu/redis"
26
-
27
- # Symbolize hash keys when parsing JSON.
28
- MultiJson.load_options = {:symbolize_keys => true}
29
28
 
30
29
  module Sensu
31
30
  module Daemon
@@ -73,10 +72,26 @@ module Sensu
73
72
  end
74
73
  end
75
74
 
75
+ # Print the Sensu settings and immediately exit the process. This
76
+ # method is used while troubleshooting configuration issues,
77
+ # triggered by a CLI argument, e.g. `--print_config`. Sensu
78
+ # settings with sensitive values (e.g. passwords) are first
79
+ # redacted.
80
+ #
81
+ # @param settings [Object]
82
+ def print_settings(settings)
83
+ redacted_settings = redact_sensitive(settings.to_hash)
84
+ @logger.warn("outputting compiled configuration and exiting")
85
+ puts Sensu::JSON.dump(redacted_settings, :pretty => true)
86
+ exit
87
+ end
88
+
76
89
  # Load Sensu settings and validate them. If there are validation
77
90
  # failures, log them (concerns), then cause the Sensu process to
78
91
  # exit (2). This method creates the settings instance variable:
79
- # `@settings`.
92
+ # `@settings`. If the `print_config` option is true, this method
93
+ # calls `print_settings()` to output the compiled configuration
94
+ # settings and then exit the process.
80
95
  #
81
96
  # https://github.com/sensu/sensu-settings
82
97
  #
@@ -91,6 +106,7 @@ module Sensu
91
106
  @logger.fatal("SENSU NOT RUNNING!")
92
107
  exit 2
93
108
  end
109
+ print_settings(@settings) if options[:print_config]
94
110
  end
95
111
 
96
112
  # Load Sensu extensions and log any concerns. Set the logger and
@@ -176,6 +192,9 @@ module Sensu
176
192
  # method creates the transport instance variable: `@transport`.
177
193
  #
178
194
  # https://github.com/sensu/sensu-transport
195
+ #
196
+ # @yield [Object] passes initialized and connected Transport
197
+ # connection object to the callback/block.
179
198
  def setup_transport
180
199
  transport_name = @settings[:transport][:name]
181
200
  transport_settings = @settings[transport_name]
@@ -184,24 +203,27 @@ module Sensu
184
203
  :settings => transport_settings
185
204
  })
186
205
  Transport.logger = @logger
187
- @transport = Transport.connect(transport_name, transport_settings)
188
- @transport.on_error do |error|
189
- @logger.fatal("transport connection error", :error => error.to_s)
190
- if @settings[:transport][:reconnect_on_error]
191
- @transport.reconnect
192
- else
193
- stop
206
+ Transport.connect(transport_name, transport_settings) do |connection|
207
+ @transport = connection
208
+ @transport.on_error do |error|
209
+ @logger.error("transport connection error", :error => error.to_s)
210
+ if @settings[:transport][:reconnect_on_error]
211
+ @transport.reconnect
212
+ else
213
+ stop
214
+ end
194
215
  end
195
- end
196
- @transport.before_reconnect do
197
- unless testing?
198
- @logger.warn("reconnecting to transport")
199
- pause
216
+ @transport.before_reconnect do
217
+ unless testing?
218
+ @logger.warn("reconnecting to transport")
219
+ pause
220
+ end
200
221
  end
201
- end
202
- @transport.after_reconnect do
203
- @logger.info("reconnected to transport")
204
- resume
222
+ @transport.after_reconnect do
223
+ @logger.info("reconnected to transport")
224
+ resume
225
+ end
226
+ yield(@transport)
205
227
  end
206
228
  end
207
229
 
@@ -210,22 +232,29 @@ module Sensu
210
232
  # service will stop gracefully in the event of a Redis error, and
211
233
  # pause/resume in the event of connectivity issues. This method
212
234
  # creates the Redis instance variable: `@redis`.
235
+ #
236
+ # https://github.com/sensu/sensu-redis
237
+ #
238
+ # @yield [Object] passes initialized and connected Redis
239
+ # connection object to the callback/block.
213
240
  def setup_redis
214
241
  @logger.debug("connecting to redis", :settings => @settings[:redis])
215
- @redis = Redis.connect(@settings[:redis])
216
- @redis.on_error do |error|
217
- @logger.fatal("redis connection error", :error => error.to_s)
218
- stop
219
- end
220
- @redis.before_reconnect do
221
- unless testing?
222
- @logger.warn("reconnecting to redis")
223
- pause
242
+ Redis.connect(@settings[:redis]) do |connection|
243
+ @redis = connection
244
+ @redis.on_error do |error|
245
+ @logger.error("redis connection error", :error => error.to_s)
224
246
  end
225
- end
226
- @redis.after_reconnect do
227
- @logger.info("reconnected to redis")
228
- resume
247
+ @redis.before_reconnect do
248
+ unless testing?
249
+ @logger.warn("reconnecting to redis")
250
+ pause
251
+ end
252
+ end
253
+ @redis.after_reconnect do
254
+ @logger.info("reconnected to redis")
255
+ resume
256
+ end
257
+ yield(@redis)
229
258
  end
230
259
  end
231
260
 
@@ -3,6 +3,8 @@ require "sensu/server/sandbox"
3
3
  module Sensu
4
4
  module Server
5
5
  module Filter
6
+ EVAL_PREFIX = "eval:".freeze
7
+
6
8
  # Determine if a period of time (window) is subdued. The
7
9
  # provided condition must have a `:begin` and `:end` time, eg.
8
10
  # "11:30:00 PM", or `false` will be returned.
@@ -165,28 +167,63 @@ module Sensu
165
167
  end
166
168
  end
167
169
 
168
- # Ruby eval() a string containing an expression, within the
170
+ # Process a filter eval attribute, a Ruby `eval()` string
171
+ # containing an expression to be evaluated within the
172
+ # scope/context of a sandbox. This methods strips away the
173
+ # expression prefix, `eval:`, and substitues any dot notation
174
+ # tokens with the corresponding event data values. If there are
175
+ # unmatched tokens, this method will return `nil`.
176
+ #
177
+ # @event [Hash]
178
+ # @raw_eval_string [String]
179
+ # @return [String] processed eval string.
180
+ def process_eval_string(event, raw_eval_string)
181
+ eval_string = raw_eval_string.slice(5..-1)
182
+ eval_string, unmatched_tokens = substitute_tokens(eval_string, event)
183
+ if unmatched_tokens.empty?
184
+ eval_string
185
+ else
186
+ @logger.error("filter eval unmatched tokens", {
187
+ :raw_eval_string => raw_eval_string,
188
+ :unmatched_tokens => unmatched_tokens,
189
+ :event => event
190
+ })
191
+ nil
192
+ end
193
+ end
194
+
195
+ # Ruby `eval()` a string containing an expression, within the
169
196
  # scope/context of a sandbox. This method is for filter
170
197
  # attribute values starting with "eval:", with the Ruby
171
198
  # expression following the colon. A single variable is provided
172
199
  # to the expression, `value`, equal to the corresponding event
173
- # attribute value. The expression is expected to return a
174
- # boolean value.
200
+ # attribute value. Dot notation tokens in the expression, e.g.
201
+ # `:::mysql.user:::`, are substituted with the corresponding
202
+ # event data values prior to evaluation. The expression is
203
+ # expected to return a boolean value.
175
204
  #
205
+ # @param event [Hash]
176
206
  # @param raw_eval_string [String] containing the Ruby
177
207
  # expression to be evaluated.
178
- # @param value [Object] of the corresponding event attribute.
208
+ # @param raw_value [Object] of the corresponding event
209
+ # attribute value.
179
210
  # @return [TrueClass, FalseClass]
180
- def eval_attribute_value(raw_eval_string, value)
181
- begin
182
- eval_string = raw_eval_string.gsub(/\Aeval:(\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
- })
211
+ def eval_attribute_value(event, raw_eval_string, raw_value)
212
+ eval_string = process_eval_string(event, raw_eval_string)
213
+ unless eval_string.nil?
214
+ begin
215
+ value = Marshal.load(Marshal.dump(raw_value))
216
+ !!Sandbox.eval(eval_string, value)
217
+ rescue => error
218
+ @logger.error("filter attribute eval error", {
219
+ :event => event,
220
+ :raw_eval_string => raw_eval_string,
221
+ :raw_value => raw_value,
222
+ :error => error.to_s
223
+ })
224
+ false
225
+ end
226
+ else
190
227
  false
191
228
  end
192
229
  end
@@ -197,21 +234,23 @@ module Sensu
197
234
  # key/value pairs (recursive), have equal string values, or
198
235
  # evaluate to true (Ruby eval).
199
236
  #
200
- # @param hash_one [Hash]
201
- # @param hash_two [Hash]
237
+ # @param event [Hash]
238
+ # @param filter_attributes [Object]
239
+ # @param event_attributes [Object]
202
240
  # @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]
241
+ def filter_attributes_match?(event, filter_attributes, event_attributes=nil)
242
+ event_attributes ||= event
243
+ filter_attributes.all? do |key, value_one|
244
+ value_two = event_attributes[key]
206
245
  case
207
246
  when value_one == value_two
208
247
  true
209
248
  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
249
+ filter_attributes_match?(event, value_one, value_two)
250
+ when value_one.to_s == value_two.to_s
212
251
  true
213
- when value_one.is_a?(String) && value_one.start_with?("eval:")
214
- eval_attribute_value(value_one, value_two)
252
+ when value_one.is_a?(String) && value_one.start_with?(EVAL_PREFIX)
253
+ eval_attribute_value(event, value_one, value_two)
215
254
  else
216
255
  false
217
256
  end
@@ -236,7 +275,7 @@ module Sensu
236
275
  case
237
276
  when @settings.filter_exists?(filter_name)
238
277
  filter = @settings[:filters][filter_name]
239
- matched = filter_attributes_match?(filter[:attributes], event)
278
+ matched = filter_attributes_match?(event, filter[:attributes])
240
279
  yield(filter[:negate] ? matched : !matched)
241
280
  when @extensions.filter_exists?(filter_name)
242
281
  extension = @extensions[:filters][filter_name]
@@ -40,7 +40,7 @@ module Sensu
40
40
  # @param callback [Proc] to call when the mutator executes
41
41
  # successfully.
42
42
  def pipe_mutator(mutator, event, &callback)
43
- options = {:data => MultiJson.dump(event), :timeout => mutator[:timeout]}
43
+ options = {:data => Sensu::JSON.dump(event), :timeout => mutator[:timeout]}
44
44
  block = mutator_callback(mutator, event, &callback)
45
45
  Spawn.process(mutator[:command], options, &block)
46
46
  end
@@ -43,6 +43,20 @@ module Sensu
43
43
  @handling_event_count = 0
44
44
  end
45
45
 
46
+ # Set up the Redis and Transport connection objects, `@redis`
47
+ # and `@transport`. This method "drys" up many instances of
48
+ # `setup_redis()` and `setup_transport()`.
49
+ #
50
+ # @yield callback/block called after connecting to Redis and the
51
+ # Sensu Transport.
52
+ def setup_connections
53
+ setup_redis do
54
+ setup_transport do
55
+ yield
56
+ end
57
+ end
58
+ end
59
+
46
60
  # Create a registration check definition for a client. Client
47
61
  # definitions may contain `:registration` configuration,
48
62
  # containing custom attributes and handler information. By
@@ -127,10 +141,11 @@ module Sensu
127
141
  @redis.set(signature_key, client[:signature])
128
142
  end
129
143
  if signature.nil? || signature.empty? || (client[:signature] == signature)
130
- @redis.set(client_key, MultiJson.dump(client)) do
131
- @redis.sadd("clients", client[:name]) do
132
- yield(true) if block_given?
133
- end
144
+ @redis.multi
145
+ @redis.set(client_key, Sensu::JSON.dump(client))
146
+ @redis.sadd("clients", client[:name])
147
+ @redis.exec do
148
+ yield(true) if block_given?
134
149
  end
135
150
  else
136
151
  @logger.warn("invalid client signature", {
@@ -156,11 +171,11 @@ module Sensu
156
171
  @transport.subscribe(:direct, "keepalives", "keepalives", :ack => true) do |message_info, message|
157
172
  @logger.debug("received keepalive", :message => message)
158
173
  begin
159
- client = MultiJson.load(message)
174
+ client = Sensu::JSON.load(message)
160
175
  update_client_registry(client) do
161
176
  @transport.ack(message_info)
162
177
  end
163
- rescue MultiJson::ParseError => error
178
+ rescue Sensu::JSON::ParseError => error
164
179
  @logger.error("failed to parse keepalive payload", {
165
180
  :message => message,
166
181
  :error => error.to_s
@@ -273,20 +288,18 @@ module Sensu
273
288
  :check => check
274
289
  })
275
290
  result_set = "#{check[:name]}:#{check[:issued]}"
276
- result_data = MultiJson.dump(:output => check[:output], :status => check[:status])
277
- @redis.hset("aggregation:#{result_set}", client[:name], result_data) do
278
- SEVERITIES.each do |severity|
279
- @redis.hsetnx("aggregate:#{result_set}", severity, 0)
280
- end
281
- severity = (SEVERITIES[check[:status]] || "unknown")
282
- @redis.hincrby("aggregate:#{result_set}", severity, 1) do
283
- @redis.hincrby("aggregate:#{result_set}", "total", 1) do
284
- @redis.sadd("aggregates:#{check[:name]}", check[:issued]) do
285
- @redis.sadd("aggregates", check[:name])
286
- end
287
- end
288
- end
291
+ result_data = Sensu::JSON.dump(:output => check[:output], :status => check[:status])
292
+ @redis.multi
293
+ @redis.hset("aggregation:#{result_set}", client[:name], result_data)
294
+ SEVERITIES.each do |severity|
295
+ @redis.hsetnx("aggregate:#{result_set}", severity, 0)
289
296
  end
297
+ severity = (SEVERITIES[check[:status]] || "unknown")
298
+ @redis.hincrby("aggregate:#{result_set}", severity, 1)
299
+ @redis.hincrby("aggregate:#{result_set}", "total", 1)
300
+ @redis.sadd("aggregates:#{check[:name]}", check[:issued])
301
+ @redis.sadd("aggregates", check[:name])
302
+ @redis.exec
290
303
  end
291
304
 
292
305
  # Truncate check output. For metric checks, (`"type":
@@ -301,7 +314,7 @@ module Sensu
301
314
  when METRIC_CHECK_TYPE
302
315
  output_lines = check[:output].split("\n")
303
316
  output = output_lines.first || check[:output]
304
- if output_lines.size > 1 || output.length > 255
317
+ if output_lines.length > 1 || output.length > 255
305
318
  output = output[0..255] + "\n..."
306
319
  end
307
320
  check.merge(:output => output)
@@ -323,15 +336,16 @@ module Sensu
323
336
  # stored (history, etc).
324
337
  def store_check_result(client, check)
325
338
  @logger.debug("storing check result", :check => check)
326
- @redis.sadd("result:#{client[:name]}", check[:name])
327
339
  result_key = "#{client[:name]}:#{check[:name]}"
340
+ history_key = "history:#{result_key}"
328
341
  check_truncated = truncate_check_output(check)
329
- @redis.set("result:#{result_key}", MultiJson.dump(check_truncated)) do
330
- history_key = "history:#{result_key}"
331
- @redis.rpush(history_key, check[:status]) do
332
- @redis.ltrim(history_key, -21, -1)
333
- yield
334
- end
342
+ @redis.multi
343
+ @redis.sadd("result:#{client[:name]}", check[:name])
344
+ @redis.set("result:#{result_key}", Sensu::JSON.dump(check_truncated))
345
+ @redis.rpush(history_key, check[:status])
346
+ @redis.ltrim(history_key, -21, -1)
347
+ @redis.exec do
348
+ yield
335
349
  end
336
350
  end
337
351
 
@@ -355,7 +369,7 @@ module Sensu
355
369
  history_key = "history:#{client[:name]}:#{check[:name]}"
356
370
  @redis.lrange(history_key, -21, -1) do |history|
357
371
  total_state_change = 0
358
- unless history.size < 21
372
+ unless history.length < 21
359
373
  state_changes = 0
360
374
  change_weight = 0.8
361
375
  previous_status = history.first
@@ -427,7 +441,7 @@ module Sensu
427
441
  # @yieldparam event [Hash]
428
442
  def update_event_registry(client, check)
429
443
  @redis.hget("events:#{client[:name]}", check[:name]) do |event_json|
430
- stored_event = event_json ? MultiJson.load(event_json) : nil
444
+ stored_event = event_json ? Sensu::JSON.load(event_json) : nil
431
445
  flapping = check_flapping?(stored_event, check)
432
446
  event = {
433
447
  :id => random_uuid,
@@ -441,7 +455,7 @@ module Sensu
441
455
  if stored_event && check[:status] == stored_event[:check][:status]
442
456
  event[:occurrences] = stored_event[:occurrences] + 1
443
457
  end
444
- @redis.hset("events:#{client[:name]}", check[:name], MultiJson.dump(event)) do
458
+ @redis.hset("events:#{client[:name]}", check[:name], Sensu::JSON.dump(event)) do
445
459
  yield(event)
446
460
  end
447
461
  elsif stored_event
@@ -498,7 +512,7 @@ module Sensu
498
512
  client_key = result[:check][:source] || result[:client]
499
513
  @redis.get("client:#{client_key}") do |client_json|
500
514
  unless client_json.nil?
501
- client = MultiJson.load(client_json)
515
+ client = Sensu::JSON.load(client_json)
502
516
  if client[:signature]
503
517
  if client[:signature] == result[:signature]
504
518
  yield(client)
@@ -563,10 +577,10 @@ module Sensu
563
577
  @logger.debug("subscribing to results")
564
578
  @transport.subscribe(:direct, "results", "results", :ack => true) do |message_info, message|
565
579
  begin
566
- result = MultiJson.load(message)
580
+ result = Sensu::JSON.load(message)
567
581
  @logger.debug("received result", :result => result)
568
582
  process_check_result(result)
569
- rescue MultiJson::ParseError => error
583
+ rescue Sensu::JSON::ParseError => error
570
584
  @logger.error("failed to parse result payload", {
571
585
  :message => message,
572
586
  :error => error.to_s
@@ -620,7 +634,7 @@ module Sensu
620
634
  :subscribers => check[:subscribers]
621
635
  })
622
636
  check[:subscribers].each do |subscription|
623
- options = transport_publish_options(subscription, MultiJson.dump(payload))
637
+ options = transport_publish_options(subscription, Sensu::JSON.dump(payload))
624
638
  @transport.publish(*options) do |info|
625
639
  if info[:error]
626
640
  @logger.error("failed to publish check request", {
@@ -704,7 +718,7 @@ module Sensu
704
718
  @redis.get("client:#{client_name}:signature") do |signature|
705
719
  payload[:signature] = signature if signature
706
720
  @logger.debug("publishing check result", :payload => payload)
707
- @transport.publish(:direct, "results", MultiJson.dump(payload)) do |info|
721
+ @transport.publish(:direct, "results", Sensu::JSON.dump(payload)) do |info|
708
722
  if info[:error]
709
723
  @logger.error("failed to publish check result", {
710
724
  :payload => payload,
@@ -758,7 +772,7 @@ module Sensu
758
772
  clients.each do |client_name|
759
773
  @redis.get("client:#{client_name}") do |client_json|
760
774
  unless client_json.nil?
761
- client = MultiJson.load(client_json)
775
+ client = Sensu::JSON.load(client_json)
762
776
  next if client[:keepalives] == false
763
777
  check = create_keepalive_check(client)
764
778
  time_since_last_keepalive = Time.now.to_i - client[:timestamp]
@@ -810,7 +824,7 @@ module Sensu
810
824
  result_key = "#{client_name}:#{check_name}"
811
825
  @redis.get("result:#{result_key}") do |result_json|
812
826
  unless result_json.nil?
813
- check = MultiJson.load(result_json)
827
+ check = Sensu::JSON.load(result_json)
814
828
  next unless check[:ttl] && check[:executed] && !check[:force_resolve]
815
829
  time_since_last_execution = Time.now.to_i - check[:executed]
816
830
  if time_since_last_execution >= check[:ttl]
@@ -845,21 +859,21 @@ module Sensu
845
859
  @redis.smembers("aggregates") do |checks|
846
860
  checks.each do |check_name|
847
861
  @redis.smembers("aggregates:#{check_name}") do |aggregates|
848
- if aggregates.size > 20
862
+ if aggregates.length > 20
849
863
  aggregates.sort!
850
- aggregates.take(aggregates.size - 20).each do |check_issued|
851
- @redis.srem("aggregates:#{check_name}", check_issued) do
852
- result_set = "#{check_name}:#{check_issued}"
853
- @redis.del("aggregate:#{result_set}") do
854
- @redis.del("aggregation:#{result_set}") do
855
- @logger.debug("pruned aggregation", {
856
- :check => {
857
- :name => check_name,
858
- :issued => check_issued
859
- }
860
- })
861
- end
862
- end
864
+ aggregates.take(aggregates.length - 20).each do |check_issued|
865
+ result_set = "#{check_name}:#{check_issued}"
866
+ @redis.multi
867
+ @redis.srem("aggregates:#{check_name}", check_issued)
868
+ @redis.del("aggregate:#{result_set}")
869
+ @redis.del("aggregation:#{result_set}")
870
+ @redis.exec do
871
+ @logger.debug("pruned aggregation", {
872
+ :check => {
873
+ :name => check_name,
874
+ :issued => check_issued
875
+ }
876
+ })
863
877
  end
864
878
  end
865
879
  end
@@ -1059,9 +1073,9 @@ module Sensu
1059
1073
  # Start the Sensu server process, connecting to Redis, the
1060
1074
  # transport, and calling the `bootstrap()` method.
1061
1075
  def start
1062
- setup_redis
1063
- setup_transport
1064
- bootstrap
1076
+ setup_connections do
1077
+ bootstrap
1078
+ end
1065
1079
  end
1066
1080
 
1067
1081
  # Pause the Sensu server process, unless it is being paused or
@@ -2,16 +2,16 @@ module Sensu
2
2
  module Server
3
3
  module Sandbox
4
4
  # Evaluate a Ruby expression within the context of a simple
5
- # "sandbox", a Proc in a module method. Use the Ruby `$SAFE`
6
- # level of 4 when the version of Ruby is less than 2.1.0. A
7
- # single value is provided to the "sandbox".
5
+ # "sandbox", a Proc in a module method. As of Ruby 2.3.0,
6
+ # `$SAFE` no longer supports levels > 1, so its use has been
7
+ # removed from this method. A single value is provided to the
8
+ # "sandbox".
8
9
  #
9
10
  # @param expression [String] to be evaluated.
10
11
  # @param value [Object] to provide the "sandbox" with.
11
12
  # @return [Object]
12
13
  def self.eval(expression, value=nil)
13
14
  result = Proc.new do
14
- $SAFE = (RUBY_VERSION < "2.1.0" ? 4 : 3)
15
15
  Kernel.eval(expression)
16
16
  end
17
17
  result.call
@@ -1,6 +1,4 @@
1
- gem "uuidtools", "2.1.5"
2
-
3
- require "uuidtools"
1
+ require "securerandom"
4
2
 
5
3
  module Sensu
6
4
  module Utilities
@@ -50,7 +48,7 @@ module Sensu
50
48
  #
51
49
  # @return [String] random UUID.
52
50
  def random_uuid
53
- UUIDTools::UUID.random_create.to_s
51
+ ::SecureRandom.uuid
54
52
  end
55
53
 
56
54
  # Remove sensitive information from a hash (eg. passwords). By
@@ -82,5 +80,43 @@ module Sensu
82
80
  end
83
81
  hash
84
82
  end
83
+
84
+ # Traverse a hash for an attribute value, with a fallback default
85
+ # value if nil.
86
+ #
87
+ # @param tree [Hash] to traverse.
88
+ # @param path [Array] of attribute keys.
89
+ # @param default [Object] value if attribute value is nil.
90
+ # @return [Object] attribute or fallback default value.
91
+ def find_attribute_value(tree, path, default)
92
+ attribute = tree[path.shift]
93
+ if attribute.is_a?(Hash)
94
+ find_attribute_value(attribute, path, default)
95
+ else
96
+ attribute.nil? ? default : attribute
97
+ end
98
+ end
99
+
100
+ # Substitute dot notation tokens (eg. :::db.name|production:::)
101
+ # with the associated definition attribute value. Tokens can
102
+ # provide a fallback default value, following a pipe.
103
+ #
104
+ # @param tokens [String]
105
+ # @param attributes [Hash]
106
+ # @return [Array] containing the string with tokens substituted
107
+ # and an array of unmatched tokens.
108
+ def substitute_tokens(tokens, attributes)
109
+ unmatched_tokens = []
110
+ substituted = tokens.gsub(/:::([^:].*?):::/) do
111
+ token, default = $1.to_s.split("|", -1)
112
+ path = token.split(".").map(&:to_sym)
113
+ matched = find_attribute_value(attributes, path, default)
114
+ if matched.nil?
115
+ unmatched_tokens << token
116
+ end
117
+ matched
118
+ end
119
+ [substituted, unmatched_tokens]
120
+ end
85
121
  end
86
122
  end
data/sensu.gemspec CHANGED
@@ -13,17 +13,15 @@ Gem::Specification.new do |s|
13
13
  s.license = "MIT"
14
14
  s.has_rdoc = false
15
15
 
16
- s.add_dependency "json" if RUBY_VERSION < "1.9"
17
- s.add_dependency "multi_json", "1.11.2"
18
- s.add_dependency "uuidtools", "2.1.5"
19
- s.add_dependency "eventmachine", "1.0.9.1"
20
- s.add_dependency "sensu-logger", "1.1.0"
21
- s.add_dependency "sensu-settings", "3.3.0"
16
+ s.add_dependency "eventmachine", "1.2.0.1"
17
+ s.add_dependency "sensu-json", "1.1.0"
18
+ s.add_dependency "sensu-logger", "1.2.0"
19
+ s.add_dependency "sensu-settings", "3.4.0"
22
20
  s.add_dependency "sensu-extension", "1.5.0"
23
- s.add_dependency "sensu-extensions", "1.4.0"
24
- s.add_dependency "sensu-transport", "4.0.0"
21
+ s.add_dependency "sensu-extensions", "1.5.0"
22
+ s.add_dependency "sensu-transport", "5.0.0"
25
23
  s.add_dependency "sensu-spawn", "1.8.0"
26
- s.add_dependency "em-redis-unified", "1.0.1"
24
+ s.add_dependency "sensu-redis", "1.2.0"
27
25
  s.add_dependency "sinatra", "1.4.6"
28
26
  s.add_dependency "async_sinatra", "1.2.0"
29
27
  s.add_dependency "thin", "1.6.3" unless RUBY_PLATFORM =~ /java/