sensu-plugins-elasticsearch-boutetnico 1.0.4
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +1 -0
- data/LICENSE +22 -0
- data/README.md +60 -0
- data/bin/check-es-circuit-breakers.rb +151 -0
- data/bin/check-es-cluster-health.rb +132 -0
- data/bin/check-es-cluster-status.rb +177 -0
- data/bin/check-es-file-descriptors.rb +173 -0
- data/bin/check-es-heap.rb +205 -0
- data/bin/check-es-indexes.rb +89 -0
- data/bin/check-es-indices-field-count.rb +194 -0
- data/bin/check-es-indices-sizes.rb +199 -0
- data/bin/check-es-node-status.rb +137 -0
- data/bin/check-es-query-average.rb +287 -0
- data/bin/check-es-query-count.rb +275 -0
- data/bin/check-es-query-exists.rb +205 -0
- data/bin/check-es-query-ratio.rb +306 -0
- data/bin/check-es-shard-allocation-status.rb +143 -0
- data/bin/handler-es-delete-indices.rb +99 -0
- data/bin/metrics-es-cluster.rb +215 -0
- data/bin/metrics-es-node-graphite.rb +354 -0
- data/bin/metrics-es-node.rb +143 -0
- data/lib/sensu-plugins-elasticsearch.rb +3 -0
- data/lib/sensu-plugins-elasticsearch/elasticsearch-common.rb +63 -0
- data/lib/sensu-plugins-elasticsearch/elasticsearch-query.rb +153 -0
- data/lib/sensu-plugins-elasticsearch/version.rb +9 -0
- metadata +351 -0
@@ -0,0 +1,143 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Checks ElasticSearch shard allocation setting status
|
4
|
+
# ===
|
5
|
+
#
|
6
|
+
# DESCRIPTION:
|
7
|
+
# Checks the ElasticSearch shard allocation persistent and transient settings
|
8
|
+
# and will return status based on a difference in those settings.
|
9
|
+
#
|
10
|
+
# OUTPUT:
|
11
|
+
# plain-text
|
12
|
+
#
|
13
|
+
# PLATFORMS:
|
14
|
+
# Linux
|
15
|
+
#
|
16
|
+
# DEPENDENCIES:
|
17
|
+
# gem: sensu-plugin
|
18
|
+
# gem: rest-client
|
19
|
+
#
|
20
|
+
# USAGE:
|
21
|
+
#
|
22
|
+
# NOTES:
|
23
|
+
#
|
24
|
+
# LICENSE:
|
25
|
+
# Copyright 2014 Yieldbot, Inc <devops@yieldbot.com>
|
26
|
+
# Released under the same terms as Sensu (the MIT license); see LICENSE
|
27
|
+
# for details.
|
28
|
+
#
|
29
|
+
|
30
|
+
require 'sensu-plugin/check/cli'
|
31
|
+
require 'rest-client'
|
32
|
+
require 'json'
|
33
|
+
require 'base64'
|
34
|
+
|
35
|
+
#
|
36
|
+
# == Elastic Search Shard Allocation Status
|
37
|
+
#
|
38
|
+
class ESShardAllocationStatus < Sensu::Plugin::Check::CLI
|
39
|
+
option :scheme,
|
40
|
+
description: 'URI scheme',
|
41
|
+
long: '--scheme SCHEME',
|
42
|
+
default: 'http'
|
43
|
+
|
44
|
+
option :server,
|
45
|
+
description: 'Elasticsearch server',
|
46
|
+
short: '-s SERVER',
|
47
|
+
long: '--server SERVER',
|
48
|
+
default: 'localhost'
|
49
|
+
|
50
|
+
option :port,
|
51
|
+
description: 'Port',
|
52
|
+
short: '-p PORT',
|
53
|
+
long: '--port PORT',
|
54
|
+
default: '9200'
|
55
|
+
|
56
|
+
option :allow_non_master,
|
57
|
+
description: 'Allow check to run on non-master nodes',
|
58
|
+
short: '-a',
|
59
|
+
long: '--allow-non-master',
|
60
|
+
default: false
|
61
|
+
|
62
|
+
option :timeout,
|
63
|
+
description: 'Sets the connection timeout for REST client',
|
64
|
+
short: '-t SECS',
|
65
|
+
long: '--timeout SECS',
|
66
|
+
proc: proc(&:to_i),
|
67
|
+
default: 45
|
68
|
+
|
69
|
+
option :user,
|
70
|
+
description: 'Elasticsearch User',
|
71
|
+
short: '-u USER',
|
72
|
+
long: '--user USER'
|
73
|
+
|
74
|
+
option :password,
|
75
|
+
description: 'Elasticsearch Password',
|
76
|
+
short: '-P PASS',
|
77
|
+
long: '--password PASS'
|
78
|
+
|
79
|
+
option :cert_file,
|
80
|
+
description: 'Cert file to use',
|
81
|
+
long: '--cert-file CERT'
|
82
|
+
|
83
|
+
def get_es_resource(resource)
|
84
|
+
headers = {}
|
85
|
+
if config[:user] && config[:password]
|
86
|
+
auth = 'Basic ' + Base64.strict_encode64("#{config[:user]}:#{config[:password]}").chomp
|
87
|
+
headers = { 'Authorization' => auth }
|
88
|
+
end
|
89
|
+
|
90
|
+
r = if config[:cert_file]
|
91
|
+
RestClient::Resource.new("#{config[:scheme]}://#{config[:server]}:#{config[:port]}#{resource}",
|
92
|
+
ssl_ca_file: config[:cert_file].to_s,
|
93
|
+
timeout: config[:timeout],
|
94
|
+
headers: headers)
|
95
|
+
else
|
96
|
+
RestClient::Resource.new("#{config[:scheme]}://#{config[:server]}:#{config[:port]}#{resource}",
|
97
|
+
timeout: config[:timeout],
|
98
|
+
headers: headers)
|
99
|
+
end
|
100
|
+
JSON.parse(r.get)
|
101
|
+
rescue Errno::ECONNREFUSED
|
102
|
+
warning 'Connection refused'
|
103
|
+
rescue RestClient::RequestTimeout
|
104
|
+
critical 'Connection timed out'
|
105
|
+
rescue RestClient::ServiceUnavailable
|
106
|
+
critical 'Service is unavailable'
|
107
|
+
rescue Errno::ECONNRESET
|
108
|
+
critical 'Connection reset by peer'
|
109
|
+
end
|
110
|
+
|
111
|
+
def master?
|
112
|
+
state = get_es_resource('/_cluster/state/master_node')
|
113
|
+
local = get_es_resource('/_nodes/_local')
|
114
|
+
local['nodes'].keys.first == state['master_node']
|
115
|
+
end
|
116
|
+
|
117
|
+
def get_status(type)
|
118
|
+
settings = get_es_resource('/_cluster/settings')
|
119
|
+
# Get the status for the given type, or default to 'all'
|
120
|
+
# which is the ES default
|
121
|
+
begin
|
122
|
+
settings[type]['cluster']['routing']['allocation']['enable'].downcase
|
123
|
+
rescue StandardError
|
124
|
+
'all'
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def run
|
129
|
+
if config[:allow_non_master] || master?
|
130
|
+
transient = get_status('transient')
|
131
|
+
persistent = get_status('persistent')
|
132
|
+
|
133
|
+
if transient == persistent
|
134
|
+
ok "Persistent and transient allocation match: #{persistent}"
|
135
|
+
else
|
136
|
+
critical "Persistent(#{persistent}) and transient(#{transient}) \
|
137
|
+
shard allocation do not match."
|
138
|
+
end
|
139
|
+
else
|
140
|
+
ok 'Not the master'
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# handler-es-delete-indices.rb
|
4
|
+
#
|
5
|
+
# DESCRIPTION:
|
6
|
+
# This handler deletes indices.
|
7
|
+
#
|
8
|
+
# OUTPUT:
|
9
|
+
# plain text
|
10
|
+
#
|
11
|
+
# PLATFORMS:
|
12
|
+
# Linux
|
13
|
+
#
|
14
|
+
# DEPENDENCIES:
|
15
|
+
# gem: sensu-plugin
|
16
|
+
# gem: elasticsearch
|
17
|
+
# gem: aws_es_transport
|
18
|
+
#
|
19
|
+
# USAGE:
|
20
|
+
# Deletes the indices given to it from a check output and a configured
|
21
|
+
# regex, and then deletes the indices matched.
|
22
|
+
#
|
23
|
+
# NOTES:
|
24
|
+
#
|
25
|
+
# LICENSE:
|
26
|
+
# Brendan Leon Gibat <brendan.gibat@gmail.com>
|
27
|
+
# Released under the same terms as Sensu (the MIT license); see LICENSE
|
28
|
+
# for details.
|
29
|
+
#
|
30
|
+
|
31
|
+
require 'sensu-handler'
|
32
|
+
require 'elasticsearch'
|
33
|
+
require 'aws_es_transport'
|
34
|
+
require 'sensu-plugins-elasticsearch'
|
35
|
+
|
36
|
+
class ESIndexCleanup < Sensu::Handler
|
37
|
+
include ElasticsearchCommon
|
38
|
+
|
39
|
+
option :transport,
|
40
|
+
long: '--transport TRANSPORT',
|
41
|
+
description: 'Transport to use to communicate with ES. Use "AWS" for signed AWS transports.'
|
42
|
+
|
43
|
+
option :region,
|
44
|
+
long: '--region REGION',
|
45
|
+
description: 'Region (necessary for AWS Transport)'
|
46
|
+
|
47
|
+
option :host,
|
48
|
+
description: 'Elasticsearch host',
|
49
|
+
short: '-h HOST',
|
50
|
+
long: '--host HOST',
|
51
|
+
default: 'localhost'
|
52
|
+
|
53
|
+
option :port,
|
54
|
+
description: 'Elasticsearch port',
|
55
|
+
short: '-p PORT',
|
56
|
+
long: '--port PORT',
|
57
|
+
proc: proc(&:to_i),
|
58
|
+
default: 9200
|
59
|
+
|
60
|
+
option :scheme,
|
61
|
+
description: 'Elasticsearch connection scheme, defaults to https for authenticated connections',
|
62
|
+
short: '-s SCHEME',
|
63
|
+
long: '--scheme SCHEME'
|
64
|
+
|
65
|
+
option :password,
|
66
|
+
description: 'Elasticsearch connection password',
|
67
|
+
short: '-P PASSWORD',
|
68
|
+
long: '--password PASSWORD'
|
69
|
+
|
70
|
+
option :user,
|
71
|
+
description: 'Elasticsearch connection user',
|
72
|
+
short: '-u USER',
|
73
|
+
long: '--user USER'
|
74
|
+
|
75
|
+
option :timeout,
|
76
|
+
description: 'Elasticsearch query timeout in seconds',
|
77
|
+
short: '-t TIMEOUT',
|
78
|
+
long: '--timeout TIMEOUT',
|
79
|
+
proc: proc(&:to_i),
|
80
|
+
default: 60
|
81
|
+
|
82
|
+
option :event_regex,
|
83
|
+
description: 'Elasticsearch connection user',
|
84
|
+
short: '-e EVENT_REGEX',
|
85
|
+
long: '--event-regex EVENT_REGEX',
|
86
|
+
default: 'INDEX\[([^\]]+)\]'
|
87
|
+
|
88
|
+
def handle
|
89
|
+
event_regex = Regexp.new(config[:event_regex])
|
90
|
+
indices_to_delete = @event['check']['output'].scan(event_regex).flatten
|
91
|
+
if !indices_to_delete.nil? && !indices_to_delete.empty?
|
92
|
+
|
93
|
+
puts("Deleting indices: [ #{indices_to_delete.sort.join(', ')} ]")
|
94
|
+
client.indices.delete index: indices_to_delete
|
95
|
+
else
|
96
|
+
puts('No indices matched pattern to delete.')
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,215 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# es-cluster-metrics
|
4
|
+
#
|
5
|
+
# DESCRIPTION:
|
6
|
+
# This plugin uses the ES API to collect metrics, producing a JSON
|
7
|
+
# document which is outputted to STDOUT. An exit status of 0 indicates
|
8
|
+
# the plugin has successfully collected and produced metrics.
|
9
|
+
#
|
10
|
+
# OUTPUT:
|
11
|
+
# metric data
|
12
|
+
#
|
13
|
+
# PLATFORMS:
|
14
|
+
# Linux
|
15
|
+
#
|
16
|
+
# DEPENDENCIES:
|
17
|
+
# gem: sensu-plugin
|
18
|
+
# gem: rest-client
|
19
|
+
#
|
20
|
+
# USAGE:
|
21
|
+
# #YELLOW
|
22
|
+
#
|
23
|
+
# NOTES:
|
24
|
+
#
|
25
|
+
# LICENSE:
|
26
|
+
# Copyright 2011 Sonian, Inc <chefs@sonian.net>
|
27
|
+
# Released under the same terms as Sensu (the MIT license); see LICENSE
|
28
|
+
# for details.
|
29
|
+
#
|
30
|
+
|
31
|
+
require 'sensu-plugin/metric/cli'
|
32
|
+
require 'rest-client'
|
33
|
+
require 'json'
|
34
|
+
require 'base64'
|
35
|
+
|
36
|
+
#
|
37
|
+
# ES Cluster Metrics
|
38
|
+
#
|
39
|
+
class ESClusterMetrics < Sensu::Plugin::Metric::CLI::Graphite
|
40
|
+
option :scheme,
|
41
|
+
description: 'Metric naming scheme, text to prepend to metric',
|
42
|
+
short: '-s SCHEME',
|
43
|
+
long: '--scheme SCHEME',
|
44
|
+
default: "#{Socket.gethostname}.elasticsearch.cluster"
|
45
|
+
|
46
|
+
option :host,
|
47
|
+
description: 'Elasticsearch host',
|
48
|
+
short: '-h HOST',
|
49
|
+
long: '--host HOST',
|
50
|
+
default: 'localhost'
|
51
|
+
|
52
|
+
option :port,
|
53
|
+
description: 'Elasticsearch port',
|
54
|
+
short: '-p PORT',
|
55
|
+
long: '--port PORT',
|
56
|
+
proc: proc(&:to_i),
|
57
|
+
default: 9200
|
58
|
+
|
59
|
+
option :timeout,
|
60
|
+
description: 'Sets the connection timeout for REST client',
|
61
|
+
short: '-t SECS',
|
62
|
+
long: '--timeout SECS',
|
63
|
+
proc: proc(&:to_i),
|
64
|
+
default: 30
|
65
|
+
|
66
|
+
option :allow_non_master,
|
67
|
+
description: 'Allow check to run on non-master nodes',
|
68
|
+
short: '-a',
|
69
|
+
long: '--allow-non-master',
|
70
|
+
default: false
|
71
|
+
|
72
|
+
option :enable_percolate,
|
73
|
+
description: 'Enables percolator stats (ES 2 and older only)',
|
74
|
+
short: '-o',
|
75
|
+
long: '--enable-percolate',
|
76
|
+
default: false
|
77
|
+
|
78
|
+
option :user,
|
79
|
+
description: 'Elasticsearch User',
|
80
|
+
short: '-u USER',
|
81
|
+
long: '--user USER'
|
82
|
+
|
83
|
+
option :password,
|
84
|
+
description: 'Elasticsearch Password',
|
85
|
+
short: '-P PASS',
|
86
|
+
long: '--password PASS'
|
87
|
+
|
88
|
+
option :https,
|
89
|
+
description: 'Enables HTTPS',
|
90
|
+
short: '-e',
|
91
|
+
long: '--https'
|
92
|
+
|
93
|
+
option :cert_file,
|
94
|
+
description: 'Cert file to use',
|
95
|
+
long: '--cert-file CERT_FILE'
|
96
|
+
|
97
|
+
def acquire_es_version
|
98
|
+
info = get_es_resource('/')
|
99
|
+
info['version']['number']
|
100
|
+
end
|
101
|
+
|
102
|
+
def get_es_resource(resource)
|
103
|
+
headers = {}
|
104
|
+
if config[:user] && config[:password]
|
105
|
+
auth = 'Basic ' + Base64.strict_encode64("#{config[:user]}:#{config[:password]}").chomp
|
106
|
+
headers = { 'Authorization' => auth }
|
107
|
+
end
|
108
|
+
|
109
|
+
protocol = if config[:https]
|
110
|
+
'https'
|
111
|
+
else
|
112
|
+
'http'
|
113
|
+
end
|
114
|
+
|
115
|
+
r = if config[:cert_file]
|
116
|
+
RestClient::Resource.new("#{protocol}://#{config[:host]}:#{config[:port]}#{resource}",
|
117
|
+
ssl_ca_file: config[:cert_file].to_s,
|
118
|
+
timeout: config[:timeout],
|
119
|
+
headers: headers)
|
120
|
+
else
|
121
|
+
RestClient::Resource.new("#{protocol}://#{config[:host]}:#{config[:port]}#{resource}",
|
122
|
+
timeout: config[:timeout],
|
123
|
+
headers: headers)
|
124
|
+
end
|
125
|
+
::JSON.parse(r.get)
|
126
|
+
rescue Errno::ECONNREFUSED
|
127
|
+
warning 'Connection refused'
|
128
|
+
rescue RestClient::RequestTimeout
|
129
|
+
warning 'Connection timed out'
|
130
|
+
end
|
131
|
+
|
132
|
+
def master?
|
133
|
+
state = if Gem::Version.new(acquire_es_version) >= Gem::Version.new('3.0.0')
|
134
|
+
get_es_resource('/_cluster/state/master_node')
|
135
|
+
else
|
136
|
+
get_es_resource('/_cluster/state?filter_routing_table=true&filter_metadata=true&filter_indices=true')
|
137
|
+
end
|
138
|
+
local = if Gem::Version.new(acquire_es_version) >= Gem::Version.new('1.0.0')
|
139
|
+
get_es_resource('/_nodes/_local')
|
140
|
+
else
|
141
|
+
get_es_resource('/_cluster/nodes/_local')
|
142
|
+
end
|
143
|
+
local['nodes'].keys.first == state['master_node']
|
144
|
+
end
|
145
|
+
|
146
|
+
def acquire_health
|
147
|
+
health = get_es_resource('/_cluster/health').reject { |k, _v| %w[cluster_name timed_out].include?(k) }
|
148
|
+
health['status'] = %w[red yellow green].index(health['status'])
|
149
|
+
health
|
150
|
+
end
|
151
|
+
|
152
|
+
def acquire_document_count
|
153
|
+
document_count = get_es_resource('/_stats/docs')
|
154
|
+
count = document_count['_all']['total']
|
155
|
+
if count.empty?
|
156
|
+
return 0
|
157
|
+
else
|
158
|
+
return count['docs']['count']
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def acquire_cluster_metrics
|
163
|
+
cluster_stats = get_es_resource('/_cluster/stats')
|
164
|
+
cluster_metrics = Hash.new { |h, k| h[k] = {} }
|
165
|
+
cluster_metrics['fs']['total_in_bytes'] = cluster_stats['nodes']['fs']['total_in_bytes']
|
166
|
+
cluster_metrics['fs']['free_in_bytes'] = cluster_stats['nodes']['fs']['free_in_bytes']
|
167
|
+
cluster_metrics['fs']['store_in_bytes'] = cluster_stats['indices']['store']['size_in_bytes']
|
168
|
+
cluster_metrics['fs']['disk_reads'] = cluster_stats['nodes']['fs']['disk_reads']
|
169
|
+
cluster_metrics['fs']['disk_writes'] = cluster_stats['nodes']['fs']['disk_writes']
|
170
|
+
cluster_metrics['fs']['disk_read_size_in_bytes'] = cluster_stats['nodes']['fs']['disk_read_size_in_bytes']
|
171
|
+
cluster_metrics['fs']['disk_write_size_in_bytes'] = cluster_stats['nodes']['fs']['disk_write_size_in_bytes']
|
172
|
+
cluster_metrics['fielddata']['memory_size_in_bytes'] = cluster_stats['indices']['fielddata']['memory_size_in_bytes']
|
173
|
+
cluster_metrics['fielddata']['evictions'] = cluster_stats['indices']['fielddata']['evictions']
|
174
|
+
|
175
|
+
# Elasticsearch changed the name filter_cache to query_cache in 2.0+
|
176
|
+
cache_name = Gem::Version.new(acquire_es_version) < Gem::Version.new('2.0.0') ? 'filter_cache' : 'query_cache'
|
177
|
+
|
178
|
+
cluster_metrics[cache_name]['memory_size_in_bytes'] = cluster_stats['indices'][cache_name]['memory_size_in_bytes']
|
179
|
+
cluster_metrics[cache_name]['evictions'] = cluster_stats['indices'][cache_name]['evictions']
|
180
|
+
cluster_metrics['mem'] = cluster_stats['nodes']['jvm']['mem']
|
181
|
+
|
182
|
+
if config[:enable_percolate] && Gem::Version.new(acquire_es_version) < Gem::Version.new('5.0.0')
|
183
|
+
cluster_metrics['percolate']['total'] = cluster_stats['indices']['percolate']['total']
|
184
|
+
cluster_metrics['percolate']['time_in_millis'] = cluster_stats['indices']['percolate']['time_in_millis']
|
185
|
+
cluster_metrics['percolate']['queries'] = cluster_stats['indices']['percolate']['queries']
|
186
|
+
end
|
187
|
+
cluster_metrics
|
188
|
+
end
|
189
|
+
|
190
|
+
def acquire_allocation_status
|
191
|
+
cluster_config = get_es_resource('/_cluster/settings')
|
192
|
+
transient_settings = cluster_config['transient']
|
193
|
+
if transient_settings.key?('cluster')
|
194
|
+
return %w[none new_primaries primaries all].index(transient_settings['cluster']['routing']['allocation']['enable'])
|
195
|
+
else
|
196
|
+
return nil
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def run
|
201
|
+
if config[:allow_non_master] || master?
|
202
|
+
acquire_health.each do |k, v|
|
203
|
+
output(config[:scheme] + '.' + k, v)
|
204
|
+
end
|
205
|
+
acquire_cluster_metrics.each do |cluster_metric|
|
206
|
+
cluster_metric[1].each do |k, v|
|
207
|
+
output(config[:scheme] + '.' + cluster_metric[0] + '.' + k, v || 0)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
output(config[:scheme] + '.document_count', acquire_document_count)
|
211
|
+
output(config[:scheme] + '.allocation_status', acquire_allocation_status) unless acquire_allocation_status.nil?
|
212
|
+
end
|
213
|
+
ok
|
214
|
+
end
|
215
|
+
end
|