portertech-sensu 1.10.0

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