sensu 0.28.6 → 0.29.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a1ea1cfa413a927a75a9acdbfb0a6ab81c7d8b9f
4
- data.tar.gz: fd3e79ae3331d1128f69d4830e1cd42e17535ddd
3
+ metadata.gz: 31731ea9a2311f9aecc12057e03442fb2dffca7e
4
+ data.tar.gz: ee7b95c65a89a73693717c5220bf7a515ee54634
5
5
  SHA512:
6
- metadata.gz: 230f849a14b5f777a9a022b8282dc438098f468e36bd0b0b016393927945244b6e30374a9e2362223bf6bded7692ac826380f836a04f3f77bf6997ec8ee6e9ef
7
- data.tar.gz: fed7831e688c6d1743f99bbba2cfa30daa719b8dfd2c3f5ba82890d9b61a995a0a4f6db09fdf81f0fc249eb28a1bf3cc989557cb98584447a4349987cf2a5c31
6
+ metadata.gz: b1a0e54b2e28998c7653b78f54278ec6f28c2a716fedfc8ab24b59108d33ff9998d60b77776c05e48e556b1decf43c15a2c95ee06842528ae3671cbd7957349a
7
+ data.tar.gz: d7ed4d7d2cb4794ab2933237d383eb37331dda2adaed120117c25ce36cacb7d4a4cd6e8249439d5f08c1ed52e2e63b5e48e2594603078bcf9f120ca6a52d936b
@@ -1,3 +1,74 @@
1
+ ## 0.29.0 - 2017-03-29
2
+
3
+ ### Features
4
+
5
+ Sensu server tasks, replacing the Sensu server leader functionality,
6
+ distributing certain server responsibilities amongst the running Sensu
7
+ servers. A server task can only run on one Sensu server at a time. Sensu
8
+ servers partake in an election process to become responsible for one or
9
+ more tasks. A task can failover to another Sensu server.
10
+
11
+ Sensu API response object filtering for any GET request. Filtering is done
12
+ with one or more dot notation query parameters, beginning with `filter.`,
13
+ to specify object attributes to filter by, e.g.
14
+ `/events?filter.client.environment=production&filter.check.contact=ops`.
15
+
16
+ Added API endpoint GET `/settings` to provided the APIs running
17
+ configuration. Sensitive setting values are redacted by default, unless
18
+ the query parameter `redacted` is set to `false`, e.g.
19
+ `/settings?redacted=false`.
20
+
21
+ Added support for invalidating a Sensu client when deleting it via the
22
+ Sensu API DELETE `/clients/:name` endpoint, disallowing further client
23
+ keepalives and check results until the client is either successfully
24
+ removed from the client registry or for a specified duration of time. To
25
+ invalidate a Sensu client until it is deleted, the query parameter
26
+ `invalidate` must be set to `true`, e.g.
27
+ `/clients/app01.example.com?invalidate=true`. To invalidate the client for
28
+ a certain amount of time (in seconds), the query parameter
29
+ `invalidate_expire` must be set as well, e.g.
30
+ `/clients/app01.example.com?invalidate=true&invalidate_expire=300`.
31
+
32
+ Added a Sensu settings hexdigest, exposed via the Sensu API GET `/info`
33
+ endpoint, providing a means to determine if a Sensu server's configuration
34
+ differs from the rest.
35
+
36
+ Added a proxy argument to `sensu-install`. To use a proxy for Sensu plugin
37
+ and extension installation with `sensu-install`, use the `-x` or
38
+ `--proxy` argument, e.g. `sensu-install -e statsd --proxy
39
+ http://proxy.example.com:8080`.
40
+
41
+ Added support for issuing proxy check requests via the Sensu API POST
42
+ `/request` endpoint.
43
+
44
+ The Sensu API now logs response times.
45
+
46
+ The Sensu API now returns a 405 (Method Not Allowed) when an API endpoint
47
+ does not support a HTTP request method, e.g. `PUT`, and sets the HTTP
48
+ header "Allow" to indicate which HTTP request methods are supported by the
49
+ requested endpoint.
50
+
51
+ Added a built-in filter for check dependencies, `check_dependencies`,
52
+ which implements the check dependency filtering logic in the Sensu Plugin
53
+ library.
54
+
55
+ Added default values for Sensu CLI options `config_file`
56
+ (`"/etc/sensu/config.json"`) and `config_dirs` (`["/etc/sensu/conf.d"]`).
57
+ These defaults are only applied when the associated file and/or directory
58
+ exist.
59
+
60
+ ### Other
61
+
62
+ Added a Rubocop configuration file and rake tasks for a slow introduction.
63
+
64
+ ### Fixes
65
+
66
+ The built-in filter `occurrences` now supports `refresh` for flapping
67
+ events (action `flapping`).
68
+
69
+ Force the configured Redis port to be an integer, as some users make the
70
+ mistake of using a string.
71
+
1
72
  ## 0.28.5 - 2017-03-23
2
73
 
3
74
  ### Fixes
@@ -10,7 +10,8 @@ module Sensu
10
10
  :verbose => false,
11
11
  :plugins => [],
12
12
  :extensions => [],
13
- :clean => false
13
+ :clean => false,
14
+ :proxy => nil
14
15
  }
15
16
  optparse = OptionParser.new do |opts|
16
17
  opts.on("-h", "--help", "Display this message") do
@@ -38,6 +39,9 @@ module Sensu
38
39
  opts.on("-c", "--clean", "Clean up (remove) other installed versions of the plugin(s) and/or extension(s)") do
39
40
  options[:clean] = true
40
41
  end
42
+ opts.on("-x", "--proxy PROXY", "Install Sensu plugins and extensions via a PROXY URL") do |proxy|
43
+ options[:proxy] = proxy
44
+ end
41
45
  end
42
46
  optparse.parse!(arguments)
43
47
  options
@@ -70,6 +74,7 @@ module Sensu
70
74
  gem_command << " --no-ri --no-rdoc"
71
75
  gem_command << " --verbose" if options[:verbose]
72
76
  gem_command << " --source #{options[:source]}" if options[:source]
77
+ gem_command << " --http-proxy #{options[:proxy]}" if options[:proxy]
73
78
  log gem_command if options[:verbose]
74
79
  unless system(gem_command)
75
80
  log "failed to install Sensu gem '#{gem_name}'"
@@ -1,4 +1,5 @@
1
1
  require "sensu/api/routes"
2
+ require "sensu/api/utilities/filter_response_content"
2
3
 
3
4
  gem "em-http-server", "0.1.8"
4
5
 
@@ -9,6 +10,7 @@ module Sensu
9
10
  module API
10
11
  class HTTPHandler < EM::HttpServer::Server
11
12
  include Routes
13
+ include Utilities::FilterResponseContent
12
14
 
13
15
  attr_accessor :logger, :settings, :redis, :transport
14
16
 
@@ -19,6 +21,7 @@ module Sensu
19
21
  # @result [Hash]
20
22
  def request_details
21
23
  return @request_details if @request_details
24
+ @request_start_time = Time.now.to_f
22
25
  _, remote_address = Socket.unpack_sockaddr_in(get_peername)
23
26
  @request_details = {
24
27
  :remote_address => remote_address,
@@ -40,12 +43,14 @@ module Sensu
40
43
  @logger.debug("api request", request_details)
41
44
  end
42
45
 
43
- # Log the HTTP response.
46
+ # Log the HTTP response. This method calculates the
47
+ # request/response time.
44
48
  def log_response
45
49
  @logger.info("api response", {
46
50
  :request => request_details,
47
51
  :status => @response.status,
48
- :content_length => @response.content.to_s.bytesize
52
+ :content_length => @response.content.to_s.bytesize,
53
+ :time => (Time.now.to_f - @request_start_time).round(3)
49
54
  })
50
55
  end
51
56
 
@@ -61,13 +66,20 @@ module Sensu
61
66
 
62
67
  # Parse the HTTP request query string for parameters. This
63
68
  # method creates `@params`, a hash of parsed query parameters,
64
- # used by the API routes.
69
+ # used by the API routes. This method also creates
70
+ # `@filter_params`, a hash of parsed response content filter
71
+ # parameters.
65
72
  def parse_parameters
66
73
  @params = {}
67
74
  if @http_query_string
68
75
  @http_query_string.split("&").each do |pair|
69
76
  key, value = pair.split("=")
70
77
  @params[key.to_sym] = value
78
+ if key.start_with?("filter.")
79
+ filter_param = key.sub(/^filter\./, "")
80
+ @filter_params ||= {}
81
+ @filter_params[filter_param] = value
82
+ end
71
83
  end
72
84
  end
73
85
  end
@@ -166,13 +178,17 @@ module Sensu
166
178
  # Respond to an HTTP request. The routes set `@response_status`,
167
179
  # `@response_status_string`, and `@response_content`
168
180
  # appropriately. The HTTP response status defaults to `200` with
169
- # the status string `OK`. The Sensu API only returns JSON
170
- # response content, `@response_content` is assumed to be a Ruby
171
- # object that can be serialized as JSON.
181
+ # the status string `OK`. If filter params were provided,
182
+ # `@response_content` is filtered (mutated). The Sensu API only
183
+ # returns JSON response content, `@response_content` is assumed
184
+ # to be a Ruby object that can be serialized as JSON.
172
185
  def respond
173
186
  @response.status = @response_status || 200
174
187
  @response.status_string = @response_status_string || "OK"
175
188
  if @response_content && @http_request_method != HEAD_METHOD
189
+ if @http_request_method == GET_METHOD && @filter_params
190
+ filter_response_content!
191
+ end
176
192
  @response.content_type "application/json"
177
193
  @response.content = Sensu::JSON.dump(@response_content)
178
194
  end
@@ -281,6 +297,14 @@ module Sensu
281
297
  respond
282
298
  end
283
299
 
300
+ # Respond to the HTTP request with a `405` (Method Not Allowed) response.
301
+ def method_not_allowed!(allowed_http_methods=[])
302
+ @response.headers["Allow"] = allowed_http_methods.join(", ")
303
+ @response_status = 405
304
+ @response_status_string = "Method Not Allowed"
305
+ respond
306
+ end
307
+
284
308
  # Respond to the HTTP request with a `412` (Precondition Failed)
285
309
  # response.
286
310
  def precondition_failed!
@@ -297,25 +321,63 @@ module Sensu
297
321
  respond
298
322
  end
299
323
 
324
+ # Determine the allowed HTTP methods for a route. The route
325
+ # regular expressions and associated route method calls are
326
+ # provided by `ROUTES`. This method returns an array of HTTP
327
+ # methods that have a route that matches the HTTP request URI.
328
+ #
329
+ # @return [Array]
330
+ def allowed_http_methods?
331
+ ROUTES.map { |http_method, routes|
332
+ match = routes.detect do |route|
333
+ @http_request_uri =~ route[0]
334
+ end
335
+ match ? http_method : nil
336
+ }.flatten.compact
337
+ end
338
+
339
+ # Determine the route method for the HTTP request method and
340
+ # URI. The route regular expressions and associated route method
341
+ # calls are provided by `ROUTES`. This method will return the
342
+ # first route method name (Ruby symbol) that has matching URI
343
+ # regular expression. If an HTTP method is not supported, or
344
+ # there is not a matching regular expression, `nil` will be
345
+ # returned.
346
+ #
347
+ # @return [Symbol]
348
+ def determine_route_method
349
+ if ROUTES.has_key?(@http_request_method)
350
+ route = ROUTES[@http_request_method].detect do |route|
351
+ @http_request_uri =~ route[0]
352
+ end
353
+ route ? route[1] : nil
354
+ else
355
+ nil
356
+ end
357
+ end
358
+
300
359
  # Route the HTTP request. OPTIONS HTTP requests will always
301
- # return a `200` with no response content. The route regular
302
- # expressions and associated route method calls are provided by
303
- # `ROUTES`. If a route match is not found, this method responds
304
- # with a `404` (Not Found) HTTP response.
360
+ # return a `200` with no response content. This method uses
361
+ # `determine_route_method()` to determine the symbolized route
362
+ # method to send/call. If a route method does not exist for the
363
+ # HTTP request method and URI, this method uses
364
+ # `allowed_http_methods?()` to determine if a 404 (Not Found) or
365
+ # 405 (Method Not Allowed) HTTP response should be used.
305
366
  def route_request
306
367
  if @http_request_method == OPTIONS_METHOD
307
368
  respond
308
- elsif ROUTES.has_key?(@http_request_method)
309
- route = ROUTES[@http_request_method].detect do |route|
310
- @http_request_uri =~ route[0]
311
- end
312
- unless route.nil?
313
- send(route[1])
369
+ else
370
+ route_method = determine_route_method
371
+ if route_method
372
+ send(route_method)
314
373
  else
315
- not_found!
374
+ allowed_http_methods = allowed_http_methods?
375
+ if allowed_http_methods.empty?
376
+ not_found!
377
+ else
378
+ method_not_allowed!(allowed_http_methods)
379
+ end
316
380
  end
317
- else
318
- not_found!
319
381
  end
320
382
  end
321
383
 
@@ -1,3 +1,4 @@
1
+ require "sensu/api/routes/settings"
1
2
  require "sensu/api/routes/info"
2
3
  require "sensu/api/routes/health"
3
4
  require "sensu/api/routes/clients"
@@ -13,6 +14,7 @@ require "sensu/api/routes/silenced"
13
14
  module Sensu
14
15
  module API
15
16
  module Routes
17
+ include Settings
16
18
  include Info
17
19
  include Health
18
20
  include Clients
@@ -32,6 +34,7 @@ module Sensu
32
34
  OPTIONS_METHOD = "OPTIONS".freeze
33
35
 
34
36
  GET_ROUTES = [
37
+ [SETTINGS_URI, :get_settings],
35
38
  [INFO_URI, :get_info],
36
39
  [HEALTH_URI, :get_health],
37
40
  [CLIENTS_URI, :get_clients],
@@ -113,8 +113,11 @@ module Sensu
113
113
  # DELETE /clients/:client_name
114
114
  def delete_client
115
115
  client_name = parse_uri(CLIENT_URI).first
116
- @redis.get("client:#{client_name}") do |client_json|
116
+ client_key = "client:#{client_name}"
117
+ signature_key = "#{client_key}:signature"
118
+ @redis.get(client_key) do |client_json|
117
119
  unless client_json.nil?
120
+ @redis.set(signature_key, "invalidated") if @params[:invalidate]
118
121
  @redis.hgetall("events:#{client_name}") do |events|
119
122
  events.each do |check_name, event_json|
120
123
  resolve_event(event_json)
@@ -125,8 +128,13 @@ module Sensu
125
128
  if events.empty? || attempts == 5
126
129
  @logger.info("deleting client from registry", :client_name => client_name)
127
130
  @redis.srem("clients", client_name) do
128
- @redis.del("client:#{client_name}")
129
- @redis.del("client:#{client_name}:signature")
131
+ @redis.del(client_key)
132
+ invalidate_expire = integer_parameter(@params[:invalidate_expire])
133
+ if @params[:invalidate] && invalidate_expire
134
+ @redis.expire(signature_key, invalidate_expire)
135
+ else
136
+ @redis.del(signature_key)
137
+ end
130
138
  @redis.del("events:#{client_name}")
131
139
  @redis.smembers("result:#{client_name}") do |checks|
132
140
  checks.each do |check_name|
@@ -16,7 +16,10 @@ module Sensu
16
16
  servers_info do |servers|
17
17
  @response_content = {
18
18
  :sensu => {
19
- :version => VERSION
19
+ :version => VERSION,
20
+ :settings => {
21
+ :hexdigest => @settings.hexdigest
22
+ }
20
23
  },
21
24
  :transport => transport,
22
25
  :redis => {
@@ -26,7 +26,11 @@ module Sensu
26
26
  :reason => data[:reason],
27
27
  :creator => data[:creator]
28
28
  }
29
- publish_check_request(check)
29
+ if check[:proxy_requests]
30
+ publish_proxy_check_requests(check)
31
+ else
32
+ publish_check_request(check)
33
+ end
30
34
  @response_content = {:issued => Time.now.to_i}
31
35
  accepted!
32
36
  else
@@ -0,0 +1,23 @@
1
+ require "sensu/utilities"
2
+
3
+ module Sensu
4
+ module API
5
+ module Routes
6
+ module Settings
7
+ include Utilities
8
+
9
+ SETTINGS_URI = /^\/settings$/
10
+
11
+ # GET /settings
12
+ def get_settings
13
+ if @params[:redacted] == "false"
14
+ @response_content = @settings.to_hash
15
+ else
16
+ @response_content = redact_sensitive(@settings.to_hash)
17
+ end
18
+ respond
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,44 @@
1
+ require "sensu/utilities"
2
+
3
+ module Sensu
4
+ module API
5
+ module Utilities
6
+ module FilterResponseContent
7
+ include Sensu::Utilities
8
+
9
+ # Create a nested hash from a dot notation key and value.
10
+ #
11
+ # @param dot_notation [String]
12
+ # @param value [Object]
13
+ # @return [Hash]
14
+ def dot_notation_to_hash(dot_notation, value)
15
+ hash = {}
16
+ dot_notation.split(".").reverse.each do |key|
17
+ if hash.empty?
18
+ hash = {key.to_sym => value}
19
+ else
20
+ hash = {key.to_sym => hash}
21
+ end
22
+ end
23
+ hash
24
+ end
25
+
26
+ # Filter the response content if filter parameters have been
27
+ # provided. This method mutates `@response_content`, only
28
+ # retaining array items that match the attributes provided via
29
+ # filter parameters.
30
+ def filter_response_content!
31
+ if @response_content.is_a?(Array) && !@filter_params.empty?
32
+ attributes = {}
33
+ @filter_params.each do |key, value|
34
+ attributes = deep_merge(attributes, dot_notation_to_hash(key, value))
35
+ end
36
+ @response_content.select! do |object|
37
+ attributes_match?(object, attributes, false)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -1,7 +1,11 @@
1
+ require "sensu/utilities"
2
+
1
3
  module Sensu
2
4
  module API
3
5
  module Utilities
4
6
  module PublishCheckRequest
7
+ include Sensu::Utilities
8
+
5
9
  # Determine the Sensu Transport publish options for a
6
10
  # subscription. If a subscription begins with a Transport pipe
7
11
  # type, either "direct:" or "roundrobin:", the subscription uses
@@ -33,7 +37,10 @@ module Sensu
33
37
  #
34
38
  # @param check [Hash] definition.
35
39
  def publish_check_request(check)
36
- payload = check.merge(:issued => Time.now.to_i)
40
+ payload = check.reject do |key, value|
41
+ [:subscribers, :interval].include?(key)
42
+ end
43
+ payload[:issued] = Time.now.to_i
37
44
  @logger.info("publishing check request", {
38
45
  :payload => payload,
39
46
  :subscribers => check[:subscribers]
@@ -51,6 +58,49 @@ module Sensu
51
58
  end
52
59
  end
53
60
  end
61
+
62
+ # Create and publish one or more proxy check requests. This
63
+ # method iterates through the Sensu client registry for clients
64
+ # that matched provided proxy request client attributes. A proxy
65
+ # check request is created for each client in the registry that
66
+ # matches the proxy request client attributes. Proxy check
67
+ # requests have their client tokens subsituted by the associated
68
+ # client attributes values. The check requests are published to
69
+ # the Transport via `publish_check_request()`.
70
+ #
71
+ # @param check [Hash] definition.
72
+ def publish_proxy_check_requests(check)
73
+ client_attributes = check[:proxy_requests][:client_attributes]
74
+ unless client_attributes.empty?
75
+ @redis.smembers("clients") do |clients|
76
+ clients.each do |client_name|
77
+ @redis.get("client:#{client_name}") do |client_json|
78
+ unless client_json.nil?
79
+ client = Sensu::JSON.load(client_json)
80
+ if attributes_match?(client, client_attributes)
81
+ @logger.debug("creating a proxy check request", {
82
+ :client => client,
83
+ :check => check
84
+ })
85
+ proxy_check, unmatched_tokens = object_substitute_tokens(check.dup, client)
86
+ if unmatched_tokens.empty?
87
+ proxy_check[:source] ||= client[:name]
88
+ publish_check_request(proxy_check)
89
+ else
90
+ @logger.warn("failed to publish a proxy check request", {
91
+ :reason => "unmatched client tokens",
92
+ :unmatched_tokens => unmatched_tokens,
93
+ :client => client,
94
+ :check => check
95
+ })
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
54
104
  end
55
105
  end
56
106
  end
@@ -11,6 +11,12 @@ module Sensu
11
11
  # @return [Hash] options
12
12
  def self.read(arguments=ARGV)
13
13
  options = {}
14
+ if File.exist?("/etc/sensu/config.json")
15
+ options[:config_file] = "/etc/sensu/config.json"
16
+ end
17
+ if Dir.exist?("/etc/sensu/conf.d")
18
+ options[:config_dirs] = ["/etc/sensu/conf.d"]
19
+ end
14
20
  optparse = OptionParser.new do |opts|
15
21
  opts.on("-h", "--help", "Display this message") do
16
22
  puts opts
@@ -20,10 +26,10 @@ module Sensu
20
26
  puts VERSION
21
27
  exit
22
28
  end
23
- opts.on("-c", "--config FILE", "Sensu JSON config FILE") do |file|
29
+ opts.on("-c", "--config FILE", "Sensu JSON config FILE. Default: /etc/sensu/config.json (if exists)") do |file|
24
30
  options[:config_file] = file
25
31
  end
26
- opts.on("-d", "--config_dir DIR[,DIR]", "DIR or comma-delimited DIR list for Sensu JSON config files") do |dir|
32
+ opts.on("-d", "--config_dir DIR[,DIR]", "DIR or comma-delimited DIR list for Sensu JSON config files. Default: /etc/sensu/conf.d (if exists)") do |dir|
27
33
  options[:config_dirs] = dir.split(",")
28
34
  end
29
35
  opts.on("--validate_config", "Validate the compiled configuration and exit") do
@@ -1,7 +1,7 @@
1
1
  module Sensu
2
2
  unless defined?(Sensu::VERSION)
3
3
  # Sensu release version.
4
- VERSION = "0.28.6".freeze
4
+ VERSION = "0.29.0".freeze
5
5
 
6
6
  # Sensu check severities.
7
7
  SEVERITIES = %w[ok warning critical unknown].freeze
@@ -4,12 +4,12 @@ gem "eventmachine", "1.2.2"
4
4
 
5
5
  gem "sensu-json", "2.1.0"
6
6
  gem "sensu-logger", "1.2.1"
7
- gem "sensu-settings", "9.9.0"
7
+ gem "sensu-settings", "10.0.0"
8
8
  gem "sensu-extension", "1.5.1"
9
- gem "sensu-extensions", "1.7.1"
9
+ gem "sensu-extensions", "1.9.0"
10
10
  gem "sensu-transport", "7.0.2"
11
11
  gem "sensu-spawn", "2.2.1"
12
- gem "sensu-redis", "2.1.0"
12
+ gem "sensu-redis", "2.1.1"
13
13
 
14
14
  require "time"
15
15
  require "uri"
@@ -142,6 +142,7 @@ module Sensu
142
142
  @logger.fatal("SENSU NOT RUNNING!")
143
143
  exit 2
144
144
  end
145
+ @settings.set_env!
145
146
  end
146
147
 
147
148
  # Load Sensu extensions and log any notices. Set the logger and
@@ -11,7 +11,9 @@ module Sensu
11
11
  include Mutate
12
12
  include Handle
13
13
 
14
- attr_reader :is_leader, :in_progress
14
+ attr_reader :tasks, :in_progress
15
+
16
+ TASKS = ["check_request_publisher", "client_monitor", "check_result_monitor"]
15
17
 
16
18
  STANDARD_CHECK_TYPE = "standard".freeze
17
19
 
@@ -34,14 +36,17 @@ module Sensu
34
36
  end
35
37
  end
36
38
 
37
- # Override Daemon initialize() to support Sensu server leader
38
- # election and the handling event count.
39
+ # Override Daemon initialize() to support Sensu server tasks and
40
+ # the handling event count.
39
41
  #
40
42
  # @param options [Hash]
41
43
  def initialize(options={})
42
44
  super
43
- @is_leader = false
44
- @timers[:leader] = Array.new
45
+ @tasks = []
46
+ @timers[:tasks] = {}
47
+ TASKS.each do |task|
48
+ @timers[:tasks][task.to_sym] = []
49
+ end
45
50
  @in_progress = Hash.new(0)
46
51
  end
47
52
 
@@ -150,7 +155,7 @@ module Sensu
150
155
  if (signature.nil? || signature.empty?) && client[:signature]
151
156
  @redis.set(signature_key, client[:signature])
152
157
  end
153
- if signature.nil? || signature.empty? || (client[:signature] == signature)
158
+ if signature.nil? || signature.empty? || client[:signature] == signature
154
159
  @redis.multi
155
160
  @redis.set(client_key, Sensu::JSON.dump(client))
156
161
  @redis.sadd("clients", client[:name])
@@ -429,18 +434,11 @@ module Sensu
429
434
  # @return [TrueClass, FalseClass]
430
435
  def check_flapping?(stored_event, check)
431
436
  if check.has_key?(:low_flap_threshold) && check.has_key?(:high_flap_threshold)
432
- if check[:low_flap_threshold].is_a?(Integer) && check[:high_flap_threshold].is_a?(Integer)
433
- was_flapping = stored_event && stored_event[:action] == EVENT_FLAPPING_ACTION
434
- if was_flapping
435
- check[:total_state_change] > check[:low_flap_threshold]
436
- else
437
- check[:total_state_change] >= check[:high_flap_threshold]
438
- end
437
+ was_flapping = stored_event && stored_event[:action] == EVENT_FLAPPING_ACTION
438
+ if was_flapping
439
+ check[:total_state_change] > check[:low_flap_threshold]
439
440
  else
440
- details = {:check => check}
441
- details[:client] = stored_event[:client] if stored_event
442
- @logger.error("invalid check flap thresholds", details)
443
- false
441
+ check[:total_state_change] >= check[:high_flap_threshold]
444
442
  end
445
443
  else
446
444
  false
@@ -607,7 +605,10 @@ module Sensu
607
605
  # `client_key` as the client name. Dynamically create client
608
606
  # data can be updated using the API (POST /clients/:client). If
609
607
  # a client does exist and it has a client signature, the check
610
- # result must have a matching signature or it is discarded.
608
+ # result must have a matching signature or it is discarded. If
609
+ # the client does not exist, but a client signature exists, the
610
+ # check result must have a matching signature or it is
611
+ # discarded.
611
612
  #
612
613
  # @param result [Hash] data.
613
614
  # @yield [client] callback/block to be called with client data,
@@ -633,10 +634,20 @@ module Sensu
633
634
  yield(client)
634
635
  end
635
636
  else
636
- client = create_client(client_key)
637
- client[:type] = "proxy" if result[:check][:source]
638
- update_client_registry(client) do
639
- yield(client)
637
+ @redis.get("client:#{client_key}:signature") do |signature|
638
+ if signature.nil? || signature.empty? || result[:signature] == signature
639
+ client = create_client(client_key)
640
+ client[:type] = "proxy" if result[:check][:source]
641
+ update_client_registry(client) do
642
+ yield(client)
643
+ end
644
+ else
645
+ @logger.warn("invalid check result signature", {
646
+ :result => result,
647
+ :signature => signature
648
+ })
649
+ yield(nil)
650
+ end
640
651
  end
641
652
  end
642
653
  end
@@ -843,18 +854,16 @@ module Sensu
843
854
  # creats an EventMachine timer for the request. This method will
844
855
  # be called after every check cron request for subsequent
845
856
  # requests. The timer is stored in the timer hash under
846
- # `:leader`, as check request publishing is a task for only the
847
- # Sensu server leader, so it can be cancelled etc. The check
848
- # cron request timer object is removed from the timer hash after
849
- # the request is published, to stop the timer hash from growing
850
- # infinitely.
857
+ # `:tasks`, so it can be cancelled etc. The check cron request
858
+ # timer object is removed from the timer hash after the request
859
+ # is published, to stop the timer hash from growing infinitely.
851
860
  #
852
861
  # @param check [Hash] definition.
853
862
  def schedule_check_cron_request(check)
854
863
  cron_time = determine_check_cron_time(check)
855
- @timers[:leader] << EM::Timer.new(cron_time) do |timer|
864
+ @timers[:tasks][:check_request_publisher] << EM::Timer.new(cron_time) do |timer|
856
865
  create_check_request_proc(check).call
857
- @timers[:leader].delete(timer)
866
+ @timers[:tasks][:check_request_publisher].delete(timer)
858
867
  schedule_check_cron_request(check)
859
868
  end
860
869
  end
@@ -874,17 +883,16 @@ module Sensu
874
883
  # using an intial calculated request splay EventMachine timer
875
884
  # and an EventMachine periodic timer for subsequent check
876
885
  # requests. The timers are stored in the timers hash under
877
- # `:leader`, as check request publishing is a task for only the
878
- # Sensu server leader, so they can be cancelled etc.
886
+ # `:tasks`, so they can be cancelled etc.
879
887
  #
880
888
  # @param check [Hash] definition.
881
889
  def schedule_check_interval_requests(check)
882
890
  request_splay = testing? ? 0 : calculate_check_request_splay(check)
883
891
  interval = testing? ? 0.5 : check[:interval]
884
- @timers[:leader] << EM::Timer.new(request_splay) do
892
+ @timers[:tasks][:check_request_publisher] << EM::Timer.new(request_splay) do
885
893
  create_check_request = create_check_request_proc(check)
886
894
  create_check_request.call
887
- @timers[:leader] << EM::PeriodicTimer.new(interval, &create_check_request)
895
+ @timers[:tasks][:check_request_publisher] << EM::PeriodicTimer.new(interval, &create_check_request)
888
896
  end
889
897
  end
890
898
 
@@ -1041,10 +1049,10 @@ module Sensu
1041
1049
 
1042
1050
  # Set up the client monitor, a periodic timer to run
1043
1051
  # `determine_stale_clients()` every 30 seconds. The timer is
1044
- # stored in the timers hash under `:leader`.
1052
+ # stored in the timers hash under `:tasks`.
1045
1053
  def setup_client_monitor
1046
1054
  @logger.debug("monitoring client keepalives")
1047
- @timers[:leader] << EM::PeriodicTimer.new(30) do
1055
+ @timers[:tasks][:client_monitor] << EM::PeriodicTimer.new(30) do
1048
1056
  determine_stale_clients
1049
1057
  end
1050
1058
  end
@@ -1087,31 +1095,21 @@ module Sensu
1087
1095
 
1088
1096
  # Set up the check result monitor, a periodic timer to run
1089
1097
  # `determine_stale_check_results()` every 30 seconds. The timer
1090
- # is stored in the timers hash under `:leader`.
1098
+ # is stored in the timers hash under `:tasks`.
1091
1099
  def setup_check_result_monitor(interval = 30)
1092
1100
  @logger.debug("monitoring check results")
1093
- @timers[:leader] << EM::PeriodicTimer.new(interval) do
1101
+ @timers[:tasks][:check_result_monitor] << EM::PeriodicTimer.new(interval) do
1094
1102
  determine_stale_check_results(interval)
1095
1103
  end
1096
1104
  end
1097
1105
 
1098
- # Set up the leader duties, tasks only performed by a single
1099
- # Sensu server at a time. The duties include publishing check
1100
- # requests, monitoring for stale clients, and pruning check
1101
- # result aggregations.
1102
- def leader_duties
1103
- setup_check_request_publisher
1104
- setup_client_monitor
1105
- setup_check_result_monitor
1106
- end
1107
-
1108
1106
  # Create a lock timestamp (integer), current time including
1109
- # milliseconds. This method is used by Sensu server leader
1107
+ # milliseconds. This method is used by Sensu server task
1110
1108
  # election.
1111
1109
  #
1112
1110
  # @return [Integer]
1113
1111
  def create_lock_timestamp
1114
- (Time.now.to_f * 1000).to_i
1112
+ (Time.now.to_f * 10000000).to_i
1115
1113
  end
1116
1114
 
1117
1115
  # Create/return the unique Sensu server ID for the current
@@ -1122,122 +1120,168 @@ module Sensu
1122
1120
  @server_id ||= random_uuid
1123
1121
  end
1124
1122
 
1125
- # Become the Sensu server leader, responsible for specific
1126
- # duties (`leader_duties()`). Unless the current process is
1127
- # already the leader, this method sets the leader ID stored in
1128
- # Redis to the unique random server ID for the process. If the
1129
- # leader ID in Redis is successfully updated, `@is_leader` is
1130
- # set to true and `leader_duties()` is called to begin the
1131
- # tasks/duties of the Sensu server leader.
1132
- def become_the_leader
1133
- unless @is_leader
1134
- @redis.set("leader", server_id) do
1135
- @logger.info("i am now the leader")
1136
- @is_leader = true
1137
- leader_duties
1123
+ # Setup a Sensu server task. Unless the current process is
1124
+ # already responsible for the task, this method sets the tasks
1125
+ # server ID stored in Redis to the unique random server ID for
1126
+ # the process. If the tasks server ID is successfully updated,
1127
+ # the task is added to `@tasks` for tracking purposes and the
1128
+ # task setup method is called.
1129
+ #
1130
+ # @param task [String]
1131
+ # @yield callback/block called after setting up the task.
1132
+ def setup_task(task)
1133
+ unless @tasks.include?(task)
1134
+ @redis.set("task:#{task}:server", server_id) do
1135
+ @logger.info("i am now responsible for a server task", :task => task)
1136
+ @tasks << task
1137
+ self.send("setup_#{task}".to_sym)
1138
+ yield if block_given?
1138
1139
  end
1139
1140
  else
1140
- @logger.debug("i am already the leader")
1141
+ @logger.debug("i am already responsible for a server task", :task => task)
1141
1142
  end
1142
1143
  end
1143
1144
 
1144
- # Resign as leader, if the current process is the Sensu server
1145
- # leader. This method cancels and clears the leader timers,
1146
- # those with references stored in the timers hash under
1147
- # `:leader`, and `@is_leader` is set to `false`. The leader ID
1148
- # and leader lock are not removed from Redis, as they will be
1149
- # updated when another server is elected to be the leader, this
1150
- # method does not need to handle Redis connectivity issues.
1151
- def resign_as_leader
1152
- if @is_leader
1153
- @logger.warn("resigning as leader")
1154
- @timers[:leader].each do |timer|
1145
+ # Relinquish a Sensu server task. This method cancels and
1146
+ # clears the associated task timers, those with references
1147
+ # stored in the timers hash under `:tasks`, and removes the task
1148
+ # from `@tasks`. The task server ID and lock are not removed
1149
+ # from Redis, as they will be updated when another server takes
1150
+ # reponsibility for the task, this method does not need to
1151
+ # handle Redis connectivity issues.
1152
+ #
1153
+ # @param task [String]
1154
+ def relinquish_task(task)
1155
+ if @tasks.include?(task)
1156
+ @logger.warn("relinquishing server task", :task => task)
1157
+ @timers[:tasks][task.to_sym].each do |timer|
1155
1158
  timer.cancel
1156
1159
  end
1157
- @timers[:leader].clear
1158
- @is_leader = false
1160
+ @timers[:tasks][task.to_sym].clear
1161
+ @tasks.delete(task)
1159
1162
  else
1160
- @logger.debug("not currently the leader")
1163
+ @logger.debug("not currently responsible for a server task", :task => task)
1161
1164
  end
1162
1165
  end
1163
1166
 
1164
- # Updates the Sensu server leader lock timestamp. The current
1165
- # leader ID is retrieved from Redis and compared with the server
1166
- # ID of the current process to determine if it is still the
1167
- # Sensu server leader. If the current process is still the
1168
- # leader, the leader lock timestamp is updated. If the current
1169
- # process is no longer the leader (regicide),
1170
- # `resign_as_leader()` is called for cleanup, so there is not
1171
- # more than one leader.
1172
- def update_leader_lock
1173
- @redis.get("leader") do |current_leader_id|
1174
- if current_leader_id == server_id
1175
- @redis.set("lock:leader", create_lock_timestamp) do
1176
- @logger.debug("updated leader lock timestamp")
1167
+ # Relinquish all Sensu server tasks, if any.
1168
+ def relinquish_tasks
1169
+ unless @tasks.empty?
1170
+ @tasks.dup.each do |task|
1171
+ relinquish_task(task)
1172
+ end
1173
+ else
1174
+ @logger.debug("not currently responsible for a server task")
1175
+ end
1176
+ end
1177
+
1178
+ # Updates a Sensu server task lock timestamp. The current task
1179
+ # server ID is retrieved from Redis and compared with the server
1180
+ # ID of the current process to determine if it is still
1181
+ # responsible for the task. If the current process is still
1182
+ # responsible, the task lock timestamp is updated. If the
1183
+ # current process is no longer responsible, `relinquish_task()`
1184
+ # is called for cleanup.
1185
+ #
1186
+ # @param task [String]
1187
+ def update_task_lock(task)
1188
+ @redis.get("task:#{task}:server") do |current_server_id|
1189
+ if current_server_id == server_id
1190
+ @redis.set("lock:task:#{task}", create_lock_timestamp) do
1191
+ @logger.debug("updated task lock timestamp", :task => task)
1177
1192
  end
1178
1193
  else
1179
- @logger.warn("another sensu server has been elected as leader")
1180
- resign_as_leader
1194
+ @logger.warn("another sensu server is responsible for the task", :task => task)
1195
+ relinquish_task(task)
1181
1196
  end
1182
1197
  end
1183
1198
  end
1184
1199
 
1185
- # Request a leader election, a process to determine if the
1186
- # current process is the Sensu server leader, with its
1187
- # own/unique duties. A Redis key/value is used as a central
1188
- # lock, using the "SETNX" Redis command to set the key/value if
1189
- # it does not exist, using a timestamp for the value. If the
1190
- # current process was able to create the key/value, it is the
1191
- # leader, and must do the duties of the leader. If the current
1192
- # process was not able to create the key/value, but the current
1193
- # timestamp value is equal to or over 30 seconds ago, the
1194
- # "GETSET" Redis command is used to set a new timestamp and
1195
- # fetch the previous value to compare them, to determine if it
1196
- # was set by the current process. If the current process is able
1197
- # to set the timestamp value, it becomes the leader.
1198
- def request_leader_election
1199
- @redis.setnx("lock:leader", create_lock_timestamp) do |created|
1200
+ # Set up a Sensu server task lock updater. This method uses a
1201
+ # periodic timer to update a task lock timestamp in Redis, every
1202
+ # 10 seconds. If the current process fails to keep the lock
1203
+ # timestamp updated for a task that it is responsible for,
1204
+ # another Sensu server will claim responsibility. This method is
1205
+ # called after task setup.
1206
+ #
1207
+ # @param task [String]
1208
+ def setup_task_lock_updater(task)
1209
+ @timers[:run] << EM::PeriodicTimer.new(10) do
1210
+ update_task_lock(task)
1211
+ end
1212
+ end
1213
+
1214
+ # Request a Sensu server task election, a process to determine
1215
+ # if the current process is to be responsible for the task. A
1216
+ # Redis key/value is used as a central lock, using the "SETNX"
1217
+ # Redis command to set the key/value if it does not exist, using
1218
+ # a timestamp for the value. If the current process was able to
1219
+ # create the key/value, it is elected, and is then responsible
1220
+ # for the task. If the current process was not able to create
1221
+ # the key/value, but the current timestamp value is equal to or
1222
+ # over 30 seconds ago, the "GETSET" Redis command is used to set
1223
+ # a new timestamp and fetch the previous value to compare them,
1224
+ # to determine if it was set by the current process. If the
1225
+ # current process is able to set the timestamp value, it is
1226
+ # elected. If elected, the current process sets up the task and
1227
+ # the associated task lock updater.
1228
+ #
1229
+ # @param task [String]
1230
+ # @yield callback/block called either after being elected and
1231
+ # setting up the task, or after failing to be elected.
1232
+ def request_task_election(task, &callback)
1233
+ @redis.setnx("lock:task:#{task}", create_lock_timestamp) do |created|
1200
1234
  if created
1201
- become_the_leader
1235
+ setup_task(task, &callback)
1236
+ setup_task_lock_updater(task)
1202
1237
  else
1203
- @redis.get("lock:leader") do |current_lock_timestamp|
1238
+ @redis.get("lock:task:#{task}") do |current_lock_timestamp|
1204
1239
  new_lock_timestamp = create_lock_timestamp
1205
- if new_lock_timestamp - current_lock_timestamp.to_i >= 30000
1206
- @redis.getset("lock:leader", new_lock_timestamp) do |previous_lock_timestamp|
1240
+ if new_lock_timestamp - current_lock_timestamp.to_i >= 300000000
1241
+ @redis.getset("lock:task:#{task}", new_lock_timestamp) do |previous_lock_timestamp|
1207
1242
  if previous_lock_timestamp == current_lock_timestamp
1208
- become_the_leader
1243
+ setup_task(task, &callback)
1244
+ setup_task_lock_updater(task)
1209
1245
  end
1210
1246
  end
1247
+ else
1248
+ yield if block_given?
1211
1249
  end
1212
1250
  end
1213
1251
  end
1214
1252
  end
1215
1253
  end
1216
1254
 
1217
- # Set up the leader monitor. A one-time timer is used to run
1218
- # `request_leader_exection()` in 2 seconds. A periodic timer is
1219
- # used to update the leader lock timestamp if the current
1220
- # process is the leader, or to run `request_leader_election(),
1221
- # every 10 seconds. The timers are stored in the timers hash
1222
- # under `:run`.
1223
- def setup_leader_monitor
1224
- @timers[:run] << EM::Timer.new(2) do
1225
- request_leader_election
1226
- end
1227
- @timers[:run] << EM::PeriodicTimer.new(10) do
1228
- if @is_leader
1229
- update_leader_lock
1255
+ # Request Sensu server task elections. The task list is ordered
1256
+ # by prioity. This method works through the task list serially,
1257
+ # increasing the election request delay as the current process
1258
+ # becomes responsible for one or more tasks, this is to improve
1259
+ # the initial distribution of tasks amongst Sensu servers.
1260
+ #
1261
+ # @param splay [Integer]
1262
+ def setup_task_elections(splay=10)
1263
+ tasks = TASKS.dup - @tasks
1264
+ next_task = Proc.new do
1265
+ task = tasks.shift
1266
+ if task
1267
+ delay = splay * @tasks.size
1268
+ @timers[:run] << EM::Timer.new(delay) do
1269
+ request_task_election(task, &next_task)
1270
+ end
1230
1271
  else
1231
- request_leader_election
1272
+ @timers[:run] << EM::Timer.new(10) do
1273
+ setup_task_elections(splay)
1274
+ end
1232
1275
  end
1233
1276
  end
1277
+ next_task.call
1234
1278
  end
1235
1279
 
1236
1280
  # Update the Sensu server registry, stored in Redis. This method
1237
1281
  # adds the local/current Sensu server info to the registry,
1238
- # including its id, hostname, address, if its the current
1239
- # leader, and some metrics. Sensu server registry entries expire
1240
- # in 30 seconds unless updated.
1282
+ # including its id, hostname, address, its server tasks, and
1283
+ # some metrics. Sensu server registry entries expire in 30
1284
+ # seconds unless updated.
1241
1285
  #
1242
1286
  # @yield [success] passes success status to optional
1243
1287
  # callback/block.
@@ -1250,13 +1294,19 @@ module Sensu
1250
1294
  :id => server_id,
1251
1295
  :hostname => system_hostname,
1252
1296
  :address => system_address,
1253
- :is_leader => @is_leader,
1297
+ :tasks => @tasks,
1254
1298
  :metrics => {
1255
1299
  :cpu => {
1256
1300
  :user => cpu_user,
1257
1301
  :system => cpu_system
1258
1302
  }
1259
1303
  },
1304
+ :sensu => {
1305
+ :version => VERSION,
1306
+ :settings => {
1307
+ :hexdigest => @settings.hexdigest
1308
+ }
1309
+ },
1260
1310
  :timestamp => Time.now.to_i
1261
1311
  }
1262
1312
  @redis.sadd("servers", server_id)
@@ -1304,13 +1354,13 @@ module Sensu
1304
1354
  end
1305
1355
 
1306
1356
  # Bootstrap the Sensu server process, setting up the keepalive
1307
- # and check result consumers, and attemping to become the leader
1308
- # to carry out its duties. This method sets the process/daemon
1309
- # `@state` to `:running`.
1357
+ # and check result consumers, and attemping to carry out Sensu
1358
+ # server tasks. This method sets the process/daemon `@state` to
1359
+ # `:running`.
1310
1360
  def bootstrap
1311
1361
  setup_keepalives
1312
1362
  setup_results
1313
- setup_leader_monitor
1363
+ setup_task_elections
1314
1364
  setup_server_registry_updater
1315
1365
  @state = :running
1316
1366
  end
@@ -1330,8 +1380,8 @@ module Sensu
1330
1380
  # set to `:pausing`, to indicate that it's in progress. All run
1331
1381
  # timers are cancelled, and the references are cleared. The
1332
1382
  # Sensu server will unsubscribe from all transport
1333
- # subscriptions, resign as leader (if currently the leader),
1334
- # then set the process/daemon `@state` to `:paused`.
1383
+ # subscriptions, relinquish any Sensu server tasks, then set the
1384
+ # process/daemon `@state` to `:paused`.
1335
1385
  def pause
1336
1386
  unless @state == :pausing || @state == :paused
1337
1387
  @state = :pausing
@@ -1340,7 +1390,7 @@ module Sensu
1340
1390
  end
1341
1391
  @timers[:run].clear
1342
1392
  unsubscribe
1343
- resign_as_leader
1393
+ relinquish_tasks
1344
1394
  @state = :paused
1345
1395
  end
1346
1396
  end
@@ -259,9 +259,10 @@ module Sensu
259
259
  #
260
260
  # @param object [Hash]
261
261
  # @param match_attributes [Object]
262
+ # @param support_eval [TrueClass, FalseClass]
262
263
  # @param object_attributes [Object]
263
264
  # @return [TrueClass, FalseClass]
264
- def attributes_match?(object, match_attributes, object_attributes=nil)
265
+ def attributes_match?(object, match_attributes, support_eval=true, object_attributes=nil)
265
266
  object_attributes ||= object
266
267
  match_attributes.all? do |key, value_one|
267
268
  value_two = object_attributes[key]
@@ -269,10 +270,10 @@ module Sensu
269
270
  when value_one == value_two
270
271
  true
271
272
  when value_one.is_a?(Hash) && value_two.is_a?(Hash)
272
- attributes_match?(object, value_one, value_two)
273
+ attributes_match?(object, value_one, support_eval, value_two)
273
274
  when value_one.to_s == value_two.to_s
274
275
  true
275
- when value_one.is_a?(String) && value_one.start_with?(EVAL_PREFIX)
276
+ when value_one.is_a?(String) && value_one.start_with?(EVAL_PREFIX) && support_eval
276
277
  eval_attribute_value(object, value_one, value_two)
277
278
  else
278
279
  false
@@ -15,12 +15,12 @@ Gem::Specification.new do |s|
15
15
  s.add_dependency "eventmachine", "1.2.2"
16
16
  s.add_dependency "sensu-json", "2.1.0"
17
17
  s.add_dependency "sensu-logger", "1.2.1"
18
- s.add_dependency "sensu-settings", "9.9.0"
18
+ s.add_dependency "sensu-settings", "10.0.0"
19
19
  s.add_dependency "sensu-extension", "1.5.1"
20
- s.add_dependency "sensu-extensions", "1.7.1"
20
+ s.add_dependency "sensu-extensions", "1.9.0"
21
21
  s.add_dependency "sensu-transport", "7.0.2"
22
22
  s.add_dependency "sensu-spawn", "2.2.1"
23
- s.add_dependency "sensu-redis", "2.1.0"
23
+ s.add_dependency "sensu-redis", "2.1.1"
24
24
  s.add_dependency "em-http-server", "0.1.8"
25
25
  s.add_dependency "parse-cron", "0.1.4"
26
26
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sensu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.28.6
4
+ version: 0.29.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Porter
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2017-04-28 00:00:00.000000000 Z
12
+ date: 2017-03-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: eventmachine
@@ -59,14 +59,14 @@ dependencies:
59
59
  requirements:
60
60
  - - '='
61
61
  - !ruby/object:Gem::Version
62
- version: 9.9.0
62
+ version: 10.0.0
63
63
  type: :runtime
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
67
  - - '='
68
68
  - !ruby/object:Gem::Version
69
- version: 9.9.0
69
+ version: 10.0.0
70
70
  - !ruby/object:Gem::Dependency
71
71
  name: sensu-extension
72
72
  requirement: !ruby/object:Gem::Requirement
@@ -87,14 +87,14 @@ dependencies:
87
87
  requirements:
88
88
  - - '='
89
89
  - !ruby/object:Gem::Version
90
- version: 1.7.1
90
+ version: 1.9.0
91
91
  type: :runtime
92
92
  prerelease: false
93
93
  version_requirements: !ruby/object:Gem::Requirement
94
94
  requirements:
95
95
  - - '='
96
96
  - !ruby/object:Gem::Version
97
- version: 1.7.1
97
+ version: 1.9.0
98
98
  - !ruby/object:Gem::Dependency
99
99
  name: sensu-transport
100
100
  requirement: !ruby/object:Gem::Requirement
@@ -129,14 +129,14 @@ dependencies:
129
129
  requirements:
130
130
  - - '='
131
131
  - !ruby/object:Gem::Version
132
- version: 2.1.0
132
+ version: 2.1.1
133
133
  type: :runtime
134
134
  prerelease: false
135
135
  version_requirements: !ruby/object:Gem::Requirement
136
136
  requirements:
137
137
  - - '='
138
138
  - !ruby/object:Gem::Version
139
- version: 2.1.0
139
+ version: 2.1.1
140
140
  - !ruby/object:Gem::Dependency
141
141
  name: em-http-server
142
142
  requirement: !ruby/object:Gem::Requirement
@@ -253,8 +253,10 @@ files:
253
253
  - lib/sensu/api/routes/request.rb
254
254
  - lib/sensu/api/routes/resolve.rb
255
255
  - lib/sensu/api/routes/results.rb
256
+ - lib/sensu/api/routes/settings.rb
256
257
  - lib/sensu/api/routes/silenced.rb
257
258
  - lib/sensu/api/routes/stashes.rb
259
+ - lib/sensu/api/utilities/filter_response_content.rb
258
260
  - lib/sensu/api/utilities/publish_check_request.rb
259
261
  - lib/sensu/api/utilities/publish_check_result.rb
260
262
  - lib/sensu/api/utilities/resolve_event.rb