portertech-sensu 1.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +961 -0
  3. data/MIT-LICENSE.txt +20 -0
  4. data/README.md +65 -0
  5. data/exe/sensu-api +10 -0
  6. data/exe/sensu-client +10 -0
  7. data/exe/sensu-install +195 -0
  8. data/exe/sensu-server +10 -0
  9. data/lib/sensu/api/http_handler.rb +434 -0
  10. data/lib/sensu/api/process.rb +79 -0
  11. data/lib/sensu/api/routes/aggregates.rb +196 -0
  12. data/lib/sensu/api/routes/checks.rb +44 -0
  13. data/lib/sensu/api/routes/clients.rb +171 -0
  14. data/lib/sensu/api/routes/events.rb +86 -0
  15. data/lib/sensu/api/routes/health.rb +45 -0
  16. data/lib/sensu/api/routes/info.rb +37 -0
  17. data/lib/sensu/api/routes/request.rb +44 -0
  18. data/lib/sensu/api/routes/resolve.rb +32 -0
  19. data/lib/sensu/api/routes/results.rb +153 -0
  20. data/lib/sensu/api/routes/settings.rb +23 -0
  21. data/lib/sensu/api/routes/silenced.rb +182 -0
  22. data/lib/sensu/api/routes/stashes.rb +107 -0
  23. data/lib/sensu/api/routes.rb +88 -0
  24. data/lib/sensu/api/utilities/filter_response_content.rb +44 -0
  25. data/lib/sensu/api/utilities/publish_check_request.rb +107 -0
  26. data/lib/sensu/api/utilities/publish_check_result.rb +39 -0
  27. data/lib/sensu/api/utilities/resolve_event.rb +29 -0
  28. data/lib/sensu/api/utilities/servers_info.rb +43 -0
  29. data/lib/sensu/api/utilities/transport_info.rb +43 -0
  30. data/lib/sensu/api/validators/check.rb +55 -0
  31. data/lib/sensu/api/validators/client.rb +35 -0
  32. data/lib/sensu/api/validators/invalid.rb +8 -0
  33. data/lib/sensu/cli.rb +69 -0
  34. data/lib/sensu/client/http_socket.rb +217 -0
  35. data/lib/sensu/client/process.rb +655 -0
  36. data/lib/sensu/client/socket.rb +207 -0
  37. data/lib/sensu/client/utils.rb +53 -0
  38. data/lib/sensu/client/validators/check.rb +53 -0
  39. data/lib/sensu/constants.rb +17 -0
  40. data/lib/sensu/daemon.rb +396 -0
  41. data/lib/sensu/sandbox.rb +19 -0
  42. data/lib/sensu/server/filter.rb +227 -0
  43. data/lib/sensu/server/handle.rb +201 -0
  44. data/lib/sensu/server/mutate.rb +92 -0
  45. data/lib/sensu/server/process.rb +1646 -0
  46. data/lib/sensu/server/socket.rb +54 -0
  47. data/lib/sensu/server/tessen.rb +170 -0
  48. data/lib/sensu/utilities.rb +398 -0
  49. data/lib/sensu.rb +3 -0
  50. data/sensu.gemspec +36 -0
  51. metadata +322 -0
@@ -0,0 +1,54 @@
1
+ module Sensu
2
+ module Server
3
+ class Socket < EM::Connection
4
+ # @!attribute [rw] on_success
5
+ # @return [Proc] callback to be called after the data has been
6
+ # transmitted successfully.
7
+ attr_accessor :on_success
8
+
9
+ # @!attribute [rw] on_error
10
+ # @return [Proc] callback to be called when there is an error.
11
+ attr_accessor :on_error
12
+
13
+ # Create a timeout timer to immediately close the socket
14
+ # connection and set `@timed_out` to true to indicate that the
15
+ # timeout caused the connection to close. The timeout timer is
16
+ # stored with `@timeout_timer`, so that it can be cancelled when
17
+ # the connection is closed.
18
+ #
19
+ # @param timeout [Numeric] in seconds.
20
+ def set_timeout(timeout)
21
+ @timeout_timer = EM::Timer.new(timeout) do
22
+ @timed_out = true
23
+ close_connection
24
+ end
25
+ end
26
+
27
+ # Record the current time when connected.
28
+ def connection_completed
29
+ @connected_at = Time.now.to_f
30
+ end
31
+
32
+ # Determine if the connection and data transmission was
33
+ # successful and call the appropriate callback, `@on_success`
34
+ # or `@on_error`, providing it with a message. Cancel the
35
+ # connection timeout timer `@timeout_timer`, if it is set. The
36
+ # `@connected_at` timestamp indicates that the connection was
37
+ # successful. If `@timed_out` is true, the connection was closed
38
+ # by the connection timeout, and the data is assumed to not have
39
+ # been transmitted.
40
+ def unbind
41
+ @timeout_timer.cancel if @timeout_timer
42
+ if @connected_at
43
+ if @timed_out
44
+ @on_error.call("socket timeout")
45
+ else
46
+ @on_success.call("wrote to socket")
47
+ end
48
+ else
49
+ @on_error.call("failed to connect to socket")
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,170 @@
1
+ gem "em-http-request", "1.1.5"
2
+
3
+ require "em-http-request"
4
+ require "sensu/constants"
5
+
6
+ module Sensu
7
+ module Server
8
+ class Tessen
9
+ attr_accessor :settings, :logger, :redis, :options
10
+ attr_reader :timers
11
+
12
+ # Create a new instance of Tessen. The instance variable
13
+ # `@timers` is use to track EventMachine timers for
14
+ # stopping/shutdown.
15
+ #
16
+ # @param options [Hash] containing the Sensu server Settings,
17
+ # Logger, and Redis connection.
18
+ def initialize(options={})
19
+ @timers = []
20
+ @settings = options[:settings]
21
+ @logger = options[:logger]
22
+ @redis = options[:redis]
23
+ @options = @settings.to_hash.fetch(:tessen, {})
24
+ end
25
+
26
+ # Determine if Tessen is enabled (opt-in).
27
+ #
28
+ # @return [TrueClass, FalseClass]
29
+ def enabled?
30
+ enabled = @options[:enabled] == true
31
+ unless enabled
32
+ note = "tessen collects anonymized data to help inform the sensu team about installations"
33
+ note << " - you can opt-in via configuration: {\"tessen\": {\"enabled\": true}}"
34
+ @logger.info("the tessen call-home mechanism is not enabled", :note => note)
35
+ end
36
+ enabled
37
+ end
38
+
39
+ # Run Tessen, scheduling data reports (every 6h).
40
+ def run
41
+ schedule_data_reports
42
+ end
43
+
44
+ # Stop Tessen, cancelling and clearing timers.
45
+ def stop
46
+ @timers.each do |timer|
47
+ timer.cancel
48
+ end
49
+ @timers.clear
50
+ end
51
+
52
+ # Schedule data reports, sending data to the Tessen service
53
+ # immediately and then every 6 hours after that.
54
+ def schedule_data_reports
55
+ send_data
56
+ @timers << EM::PeriodicTimer.new(21600) do
57
+ send_data
58
+ end
59
+ end
60
+
61
+ # Send data to the Tessen service.
62
+ def send_data(&block)
63
+ create_data do |data|
64
+ tessen_api_request(data, &block)
65
+ end
66
+ end
67
+
68
+ # Create data to be sent to the Tessen service.
69
+ #
70
+ # @return [Hash]
71
+ def create_data
72
+ get_install_id do |install_id|
73
+ get_client_count do |client_count|
74
+ get_server_count do |server_count|
75
+ identity_key = @options.fetch(:identity_key, "")
76
+ flavour, version = get_version_info
77
+ timestamp = Time.now.to_i
78
+ data = {
79
+ :tessen_identity_key => identity_key,
80
+ :install => {
81
+ :id => install_id,
82
+ :sensu_flavour => flavour,
83
+ :sensu_version => version
84
+ },
85
+ :metrics => {
86
+ :points => [
87
+ {
88
+ :name => "client_count",
89
+ :value => client_count,
90
+ :timestamp => timestamp
91
+ },
92
+ {
93
+ :name => "server_count",
94
+ :value => server_count,
95
+ :timestamp => timestamp
96
+ }
97
+ ]
98
+ }
99
+ }
100
+ yield data
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ # Get the Sensu installation ID. The ID is randomly generated
107
+ # and stored in Redis. This ID provides context and allows
108
+ # multiple Sensu servers to report data for the same installation.
109
+ def get_install_id
110
+ @redis.setnx("tessen:install_id", rand(36**12).to_s(36)) do |created|
111
+ @redis.get("tessen:install_id") do |install_id|
112
+ yield install_id
113
+ end
114
+ end
115
+ end
116
+
117
+ # Get the Sensu client count for the installation. This count
118
+ # currently includes proxy clients.
119
+ #
120
+ # @yield [count]
121
+ # @yieldparam [Integer] client count
122
+ def get_client_count
123
+ @redis.scard("clients") do |count|
124
+ yield count.to_i
125
+ end
126
+ end
127
+
128
+ # Get the Sensu server count for the installation.
129
+ #
130
+ # @yield [count]
131
+ # @yieldparam [Integer] server count
132
+ def get_server_count
133
+ @redis.scard("servers") do |count|
134
+ yield count.to_i
135
+ end
136
+ end
137
+
138
+ # Get the Sensu version info for the local Sensu service.
139
+ def get_version_info
140
+ if defined?(Sensu::Enterprise::VERSION)
141
+ ["enterprise", Sensu::Enterprise::VERSION]
142
+ else
143
+ ["core", Sensu::VERSION]
144
+ end
145
+ end
146
+
147
+ # Make a Tessen service API request.
148
+ #
149
+ # @param data [Hash]
150
+ def tessen_api_request(data)
151
+ @logger.debug("sending data to the tessen call-home service", {
152
+ :data => data,
153
+ :options => @options
154
+ })
155
+ connection = {}
156
+ connection[:proxy] = @options[:proxy] if @options[:proxy]
157
+ post_options = {:body => Sensu::JSON.dump(data)}
158
+ http = EM::HttpRequest.new("https://tessen.sensu.io/v1/data", connection).post(post_options)
159
+ http.callback do
160
+ @logger.debug("tessen call-home service response", :status => http.response_header.status)
161
+ yield if block_given?
162
+ end
163
+ http.errback do
164
+ @logger.debug("tessen call-home service error", :error => http.error)
165
+ yield if block_given?
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,398 @@
1
+ gem "parse-cron", "0.1.4"
2
+
3
+ require "securerandom"
4
+ require "sensu/sandbox"
5
+ require "parse-cron"
6
+ require "socket"
7
+
8
+ module Sensu
9
+ module Utilities
10
+ EVAL_PREFIX = "eval:".freeze
11
+ NANOSECOND_RESOLUTION = 9.freeze
12
+
13
+ # Determine if Sensu is being tested, using the process name.
14
+ # Sensu is being test if the process name is "rspec",
15
+ #
16
+ # @return [TrueClass, FalseClass]
17
+ def testing?
18
+ File.basename($0) == "rspec"
19
+ end
20
+
21
+ # Retry a code block until it retures true. The first attempt and
22
+ # following retries are delayed.
23
+ #
24
+ # @param wait [Numeric] time to delay block calls.
25
+ # @param block [Proc] to call that needs to return true.
26
+ def retry_until_true(wait=0.5, &block)
27
+ EM::Timer.new(wait) do
28
+ unless block.call
29
+ retry_until_true(wait, &block)
30
+ end
31
+ end
32
+ end
33
+
34
+ # Deep merge two hashes. Nested hashes are deep merged, arrays are
35
+ # concatenated and duplicate array items are removed.
36
+ #
37
+ # @param hash_one [Hash]
38
+ # @param hash_two [Hash]
39
+ # @return [Hash] deep merged hash.
40
+ def deep_merge(hash_one, hash_two)
41
+ merged = hash_one.dup
42
+ hash_two.each do |key, value|
43
+ merged[key] = case
44
+ when hash_one[key].is_a?(Hash) && value.is_a?(Hash)
45
+ deep_merge(hash_one[key], value)
46
+ when hash_one[key].is_a?(Array) && value.is_a?(Array)
47
+ (hash_one[key] + value).uniq
48
+ else
49
+ value
50
+ end
51
+ end
52
+ merged
53
+ end
54
+
55
+ # Creates a deep dup of basic ruby objects with support for walking
56
+ # hashes and arrays.
57
+ #
58
+ # @param obj [Object]
59
+ # @return [obj] a dup of the original object.
60
+ def deep_dup(obj)
61
+ if obj.class == Hash
62
+ new_obj = obj.dup
63
+ new_obj.each do |key, value|
64
+ new_obj[deep_dup(key)] = deep_dup(value)
65
+ end
66
+ new_obj
67
+ elsif obj.class == Array
68
+ arr = []
69
+ obj.each do |item|
70
+ arr << deep_dup(item)
71
+ end
72
+ arr
73
+ elsif obj.class == String
74
+ obj.dup
75
+ else
76
+ obj
77
+ end
78
+ end
79
+
80
+ # Retrieve the system hostname. If the hostname cannot be
81
+ # determined and an error is thrown, `nil` will be returned.
82
+ #
83
+ # @return [String] system hostname.
84
+ def system_hostname
85
+ ::Socket.gethostname rescue nil
86
+ end
87
+
88
+ # Retrieve the system IP address. If a valid non-loopback
89
+ # IPv4 address cannot be found and an error is thrown,
90
+ # `nil` will be returned.
91
+ #
92
+ # @return [String] system ip address
93
+ def system_address
94
+ ::Socket.ip_address_list.find { |address|
95
+ address.ipv4? && !address.ipv4_loopback?
96
+ }.ip_address rescue nil
97
+ end
98
+
99
+ # Retrieve the process CPU times. If the cpu times cannot be
100
+ # determined and an error is thrown, `[nil, nil, nil, nil]` will
101
+ # be returned.
102
+ #
103
+ # @return [Array] CPU times: utime, stime, cutime, cstime
104
+ def process_cpu_times(&callback)
105
+ determine_cpu_times = Proc.new do
106
+ ::Process.times.to_a rescue [nil, nil, nil, nil]
107
+ end
108
+ EM::defer(determine_cpu_times, callback)
109
+ end
110
+
111
+ # Generate a random universally unique identifier.
112
+ #
113
+ # @return [String] random UUID.
114
+ def random_uuid
115
+ ::SecureRandom.uuid
116
+ end
117
+
118
+ # Remove sensitive information from a hash (eg. passwords). By
119
+ # default, hash values will be redacted for the following keys:
120
+ # password, passwd, pass, api_key, api_token, access_key,
121
+ # secret_key, private_key, secret
122
+ #
123
+ # @param obj [Object] to redact sensitive value from.
124
+ # @param keys [Array] that indicate sensitive values.
125
+ # @return [Hash] hash with redacted sensitive values.
126
+ def redact_sensitive(obj, keys=nil)
127
+ keys ||= %w[
128
+ password passwd pass
129
+ api_key api_token
130
+ access_key secret_key private_key
131
+ secret
132
+ routing_key
133
+ access_token_read access_token_write access_token_path
134
+ webhook_url
135
+ nickserv_password channel_password
136
+ community
137
+ keystore_password truststore_password
138
+ proxy_password
139
+ access_key_id secret_access_key
140
+ ]
141
+ obj = obj.dup
142
+ if obj.is_a?(Hash)
143
+ obj.each do |key, value|
144
+ if keys.include?(key.to_s)
145
+ obj[key] = "REDACTED"
146
+ elsif value.is_a?(Hash) || value.is_a?(Array)
147
+ obj[key] = redact_sensitive(value, keys)
148
+ end
149
+ end
150
+ elsif obj.is_a?(Array)
151
+ obj.map! do |item|
152
+ if item.is_a?(Hash) || item.is_a?(Array)
153
+ redact_sensitive(item, keys)
154
+ else
155
+ item
156
+ end
157
+ end
158
+ end
159
+ obj
160
+ end
161
+
162
+ # Traverse a hash for an attribute value, with a fallback default
163
+ # value if nil.
164
+ #
165
+ # @param tree [Hash] to traverse.
166
+ # @param path [Array] of attribute keys.
167
+ # @param default [Object] value if attribute value is nil.
168
+ # @return [Object] attribute or fallback default value.
169
+ def find_attribute_value(tree, path, default)
170
+ attribute = tree[path.shift]
171
+ if attribute.is_a?(Hash)
172
+ find_attribute_value(attribute, path, default)
173
+ else
174
+ attribute.nil? ? default : attribute
175
+ end
176
+ end
177
+
178
+ # Substitute dot notation tokens (eg. :::db.name|production:::)
179
+ # with the associated definition attribute value. Tokens can
180
+ # provide a fallback default value, following a pipe.
181
+ #
182
+ # @param tokens [String]
183
+ # @param attributes [Hash]
184
+ # @return [Array] containing the string with tokens substituted
185
+ # and an array of unmatched tokens.
186
+ def substitute_tokens(tokens, attributes)
187
+ unmatched_tokens = []
188
+ encoded_tokens = tokens.encode("UTF-8", "binary", **{
189
+ :invalid => :replace,
190
+ :undef => :replace,
191
+ :replace => ""
192
+ })
193
+ substituted = encoded_tokens.gsub(/:::([^:].*?):::/) do
194
+ token, default = $1.to_s.split("|", 2)
195
+ path = token.split(".").map(&:to_sym)
196
+ matched = find_attribute_value(attributes, path, default)
197
+ if matched.nil?
198
+ unmatched_tokens << token
199
+ end
200
+ matched
201
+ end
202
+ [substituted, unmatched_tokens]
203
+ end
204
+
205
+ # Perform token substitution for an object. String values are
206
+ # passed to `substitute_tokens()`, arrays and sub-hashes are
207
+ # processed recursively. Numeric values are ignored.
208
+ #
209
+ # @param object [Object]
210
+ # @param attributes [Hash]
211
+ # @return [Array] containing the updated object with substituted
212
+ # values and an array of unmatched tokens.
213
+ def object_substitute_tokens(object, attributes)
214
+ unmatched_tokens = []
215
+ case object
216
+ when Hash
217
+ object.each do |key, value|
218
+ object[key], unmatched = object_substitute_tokens(value, attributes)
219
+ unmatched_tokens.push(*unmatched)
220
+ end
221
+ when Array
222
+ object.map! do |value|
223
+ value, unmatched = object_substitute_tokens(value, attributes)
224
+ unmatched_tokens.push(*unmatched)
225
+ value
226
+ end
227
+ when String
228
+ object, unmatched_tokens = substitute_tokens(object, attributes)
229
+ end
230
+ [object, unmatched_tokens.uniq]
231
+ end
232
+
233
+ # Process an eval attribute value, a Ruby `eval()` string
234
+ # containing an expression to be evaluated within the
235
+ # scope/context of a sandbox. This methods strips away the
236
+ # expression prefix, `eval:`, and substitues any dot notation
237
+ # tokens with the corresponding event data values. If there are
238
+ # unmatched tokens, this method will return `nil`.
239
+ #
240
+ # @object [Hash]
241
+ # @raw_eval_string [String]
242
+ # @return [String] processed eval string.
243
+ def process_eval_string(object, raw_eval_string)
244
+ eval_string = raw_eval_string.slice(5..-1)
245
+ eval_string, unmatched_tokens = substitute_tokens(eval_string, object)
246
+ if unmatched_tokens.empty?
247
+ eval_string
248
+ else
249
+ @logger.error("attribute value eval unmatched tokens", {
250
+ :object => object,
251
+ :raw_eval_string => raw_eval_string,
252
+ :unmatched_tokens => unmatched_tokens
253
+ })
254
+ nil
255
+ end
256
+ end
257
+
258
+ # Ruby `eval()` a string containing an expression, within the
259
+ # scope/context of a sandbox. This method is for attribute values
260
+ # starting with "eval:", with the Ruby expression following the
261
+ # colon. A single variable is provided to the expression, `value`,
262
+ # equal to the corresponding object attribute value. Dot notation
263
+ # tokens in the expression, e.g. `:::mysql.user:::`, are
264
+ # substituted with the corresponding object attribute values prior
265
+ # to evaluation. The expression is expected to return a boolean
266
+ # value.
267
+ #
268
+ # @param object [Hash]
269
+ # @param raw_eval_string [String] containing the Ruby
270
+ # expression to be evaluated.
271
+ # @param raw_value [Object] of the corresponding object
272
+ # attribute value.
273
+ # @return [TrueClass, FalseClass]
274
+ def eval_attribute_value(object, raw_eval_string, raw_value)
275
+ eval_string = process_eval_string(object, raw_eval_string)
276
+ unless eval_string.nil?
277
+ begin
278
+ value = Marshal.load(Marshal.dump(raw_value))
279
+ !!Sandbox.eval(eval_string, value)
280
+ rescue StandardError, SyntaxError => error
281
+ @logger.error("attribute value eval error", {
282
+ :object => object,
283
+ :raw_eval_string => raw_eval_string,
284
+ :raw_value => raw_value,
285
+ :error => error.to_s
286
+ })
287
+ false
288
+ end
289
+ else
290
+ false
291
+ end
292
+ end
293
+
294
+ # Determine if all attribute values match those of the
295
+ # corresponding object attributes. Attributes match if the value
296
+ # objects are equivalent, are both hashes with matching key/value
297
+ # pairs (recursive), have equal string values, or evaluate to true
298
+ # (Ruby eval).
299
+ #
300
+ # @param object [Hash]
301
+ # @param match_attributes [Object]
302
+ # @param support_eval [TrueClass, FalseClass]
303
+ # @param object_attributes [Object]
304
+ # @return [TrueClass, FalseClass]
305
+ def attributes_match?(object, match_attributes, support_eval=true, object_attributes=nil)
306
+ object_attributes ||= object
307
+ match_attributes.all? do |key, value_one|
308
+ value_two = object_attributes[key]
309
+ case
310
+ when value_one == value_two
311
+ true
312
+ when value_one.is_a?(Hash) && value_two.is_a?(Hash)
313
+ attributes_match?(object, value_one, support_eval, value_two)
314
+ when value_one.to_s == value_two.to_s
315
+ true
316
+ when value_one.is_a?(String) && value_one.start_with?(EVAL_PREFIX) && support_eval
317
+ eval_attribute_value(object, value_one, value_two)
318
+ else
319
+ false
320
+ end
321
+ end
322
+ end
323
+
324
+ # Determine if the current time falls within a time window. The
325
+ # provided condition must have a `:begin` and `:end` time, eg.
326
+ # "11:30:00 PM", or `false` will be returned.
327
+ #
328
+ # @param condition [Hash]
329
+ # @option condition [String] :begin time.
330
+ # @option condition [String] :end time.
331
+ # @return [TrueClass, FalseClass]
332
+ def in_time_window?(condition)
333
+ if condition.has_key?(:begin) && condition.has_key?(:end)
334
+ begin_time = Time.parse(condition[:begin])
335
+ end_time = Time.parse(condition[:end])
336
+ if end_time < begin_time
337
+ if Time.now < end_time
338
+ begin_time = Time.parse(*begin_time.strftime("%Y-%m-%d 00:00:00.#{Array.new(NANOSECOND_RESOLUTION, 0).join} %:z"))
339
+ else
340
+ end_time = Time.parse(*end_time.strftime("%Y-%m-%d 23:59:59.#{Array.new(NANOSECOND_RESOLUTION, 9).join} %:z"))
341
+ end
342
+ end
343
+ Time.now >= begin_time && Time.now <= end_time
344
+ else
345
+ false
346
+ end
347
+ end
348
+
349
+ # Determine if time window conditions for one or more days of the
350
+ # week are met. If a day of the week is provided, it can provide
351
+ # one or more conditions, each with a `:begin` and `:end` time,
352
+ # eg. "11:30:00 PM", or `false` will be returned.
353
+ #
354
+ # @param conditions [Hash]
355
+ # @option conditions [String] :days of the week.
356
+ # @return [TrueClass, FalseClass]
357
+ def in_time_windows?(conditions)
358
+ in_window = false
359
+ window_days = conditions[:days] || {}
360
+ if window_days[:all]
361
+ in_window = window_days[:all].any? do |condition|
362
+ in_time_window?(condition)
363
+ end
364
+ end
365
+ current_day = Time.now.strftime("%A").downcase.to_sym
366
+ if !in_window && window_days[current_day]
367
+ in_window = window_days[current_day].any? do |condition|
368
+ in_time_window?(condition)
369
+ end
370
+ end
371
+ in_window
372
+ end
373
+
374
+ # Determine if a check is subdued, by conditions set in the check
375
+ # definition. If any of the conditions are true, without an
376
+ # exception, the check is subdued.
377
+ #
378
+ # @param check [Hash] definition.
379
+ # @return [TrueClass, FalseClass]
380
+ def check_subdued?(check)
381
+ if check[:subdue]
382
+ in_time_windows?(check[:subdue])
383
+ else
384
+ false
385
+ end
386
+ end
387
+
388
+ # Determine the next check cron time.
389
+ #
390
+ # @param check [Hash] definition.
391
+ def determine_check_cron_time(check)
392
+ cron_parser = CronParser.new(check[:cron])
393
+ current_time = Time.now
394
+ next_cron_time = cron_parser.next(current_time)
395
+ next_cron_time - current_time
396
+ end
397
+ end
398
+ end
data/lib/sensu.rb ADDED
@@ -0,0 +1,3 @@
1
+ module Sensu
2
+ # A monitoring framework that aims to be simple, malleable, & scalable.
3
+ end
data/sensu.gemspec ADDED
@@ -0,0 +1,36 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.join(File.dirname(__FILE__), "lib", "sensu", "constants")
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "portertech-sensu"
6
+ s.version = Sensu::VERSION
7
+ s.authors = ["Sean Porter", "Justin Kolberg"]
8
+ s.email = ["portertech@gmail.com", "amdprophet@gmail.com"]
9
+ s.homepage = "https://sensu.io"
10
+ s.summary = "A monitoring framework"
11
+ s.description = "A monitoring framework that aims to be simple, malleable, and scalable."
12
+ s.license = "MIT"
13
+
14
+ s.add_dependency "eventmachine", "1.2.7"
15
+ s.add_dependency "portertech-sensu-json", "2.2.1"
16
+ s.add_dependency "portertech-sensu-logger", "1.4.0"
17
+ s.add_dependency "portertech-sensu-settings", "10.18.0"
18
+ s.add_dependency "sensu-extension", "1.5.2"
19
+ s.add_dependency "portertech-sensu-extensions", "1.12.0"
20
+ s.add_dependency "sensu-transport", "8.3.0"
21
+ s.add_dependency "portertech-sensu-spawn", "2.6.1"
22
+ s.add_dependency "sensu-redis", "2.4.0"
23
+ s.add_dependency "em-http-server", "0.1.8"
24
+ s.add_dependency "em-http-request", "1.1.5"
25
+ s.add_dependency "parse-cron", "0.1.4"
26
+
27
+ s.add_development_dependency "rake", "13.0.6"
28
+ s.add_development_dependency "rspec", "~> 3.12.0"
29
+ s.add_development_dependency "addressable", "2.3.8"
30
+ s.add_development_dependency "webmock", "3.3.0"
31
+
32
+ s.files = Dir.glob("{exe,lib}/**/*") + %w[sensu.gemspec README.md CHANGELOG.md MIT-LICENSE.txt]
33
+ s.executables = s.files.grep(%r{^exe/}) { |file| File.basename(file) }
34
+ s.bindir = "exe"
35
+ s.require_paths = ["lib"]
36
+ end