sensu 0.22.2-java → 0.23.0.beta-java

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.
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/