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,173 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# check-es-file-descriptors
|
4
|
+
#
|
5
|
+
# DESCRIPTION:
|
6
|
+
# This plugin checks the ElasticSearch file descriptor usage, using its API.
|
7
|
+
#
|
8
|
+
# OUTPUT:
|
9
|
+
# plain text
|
10
|
+
#
|
11
|
+
# PLATFORMS:
|
12
|
+
# Linux
|
13
|
+
#
|
14
|
+
# DEPENDENCIES:
|
15
|
+
# gem: sensu-plugin
|
16
|
+
# gem: rest-client
|
17
|
+
#
|
18
|
+
# USAGE:
|
19
|
+
# #YELLOW
|
20
|
+
#
|
21
|
+
# NOTES:
|
22
|
+
#
|
23
|
+
# LICENSE:
|
24
|
+
# Author: S. Zachariah Sprackett <zac@sprackett.com>
|
25
|
+
# Released under the same terms as Sensu (the MIT license); see LICENSE
|
26
|
+
# for details.
|
27
|
+
#
|
28
|
+
|
29
|
+
require 'sensu-plugin/check/cli'
|
30
|
+
require 'rest-client'
|
31
|
+
require 'json'
|
32
|
+
require 'base64'
|
33
|
+
|
34
|
+
#
|
35
|
+
# ES File Descriptiors
|
36
|
+
#
|
37
|
+
class ESFileDescriptors < Sensu::Plugin::Check::CLI
|
38
|
+
option :host,
|
39
|
+
description: 'Elasticsearch host',
|
40
|
+
short: '-h HOST',
|
41
|
+
long: '--host HOST',
|
42
|
+
default: 'localhost'
|
43
|
+
|
44
|
+
option :port,
|
45
|
+
description: 'Elasticsearch port',
|
46
|
+
short: '-p PORT',
|
47
|
+
long: '--port PORT',
|
48
|
+
proc: proc(&:to_i),
|
49
|
+
default: 9200
|
50
|
+
|
51
|
+
option :timeout,
|
52
|
+
description: 'Sets the connection timeout for REST client',
|
53
|
+
short: '-t SECS',
|
54
|
+
long: '--timeout SECS',
|
55
|
+
proc: proc(&:to_i),
|
56
|
+
default: 30
|
57
|
+
|
58
|
+
option :critical,
|
59
|
+
description: 'Critical percentage of FD usage',
|
60
|
+
short: '-c PERCENTAGE',
|
61
|
+
proc: proc(&:to_i),
|
62
|
+
default: 90
|
63
|
+
|
64
|
+
option :warning,
|
65
|
+
description: 'Warning percentage of FD usage',
|
66
|
+
short: '-w PERCENTAGE',
|
67
|
+
proc: proc(&:to_i),
|
68
|
+
default: 80
|
69
|
+
|
70
|
+
option :user,
|
71
|
+
description: 'Elasticsearch User',
|
72
|
+
short: '-u USER',
|
73
|
+
long: '--user USER'
|
74
|
+
|
75
|
+
option :password,
|
76
|
+
description: 'Elasticsearch Password',
|
77
|
+
short: '-P PASS',
|
78
|
+
long: '--password PASS'
|
79
|
+
|
80
|
+
option :https,
|
81
|
+
description: 'Enables HTTPS',
|
82
|
+
short: '-e',
|
83
|
+
long: '--https'
|
84
|
+
|
85
|
+
option :cert_file,
|
86
|
+
description: 'Cert file to use',
|
87
|
+
long: '--cert-file CERT'
|
88
|
+
|
89
|
+
def get_es_resource(resource)
|
90
|
+
headers = {}
|
91
|
+
if config[:user] && config[:password]
|
92
|
+
auth = 'Basic ' + Base64.strict_encode64("#{config[:user]}:#{config[:password]}").chomp
|
93
|
+
headers = { 'Authorization' => auth }
|
94
|
+
end
|
95
|
+
|
96
|
+
protocol = if config[:https]
|
97
|
+
'https'
|
98
|
+
else
|
99
|
+
'http'
|
100
|
+
end
|
101
|
+
|
102
|
+
r = if config[:cert_file]
|
103
|
+
RestClient::Resource.new("#{protocol}://#{config[:host]}:#{config[:port]}#{resource}",
|
104
|
+
ssl_ca_file: config[:cert_file].to_s,
|
105
|
+
timeout: config[:timeout],
|
106
|
+
headers: headers)
|
107
|
+
else
|
108
|
+
RestClient::Resource.new("#{protocol}://#{config[:host]}:#{config[:port]}#{resource}",
|
109
|
+
timeout: config[:timeout],
|
110
|
+
headers: headers)
|
111
|
+
end
|
112
|
+
JSON.parse(r.get)
|
113
|
+
rescue Errno::ECONNREFUSED
|
114
|
+
warning 'Connection refused'
|
115
|
+
rescue RestClient::RequestTimeout
|
116
|
+
warning 'Connection timed out'
|
117
|
+
rescue RestClient::ServiceUnavailable
|
118
|
+
warning 'Service is unavailable'
|
119
|
+
end
|
120
|
+
|
121
|
+
def acquire_es_version
|
122
|
+
info = get_es_resource('/')
|
123
|
+
info['version']['number']
|
124
|
+
end
|
125
|
+
|
126
|
+
def es_version
|
127
|
+
@es_version ||= Gem::Version.new(acquire_es_version)
|
128
|
+
end
|
129
|
+
|
130
|
+
def acquire_open_fds
|
131
|
+
stats = if es_version < Gem::Version.new('5.0.0')
|
132
|
+
get_es_resource('/_nodes/_local/stats?process=true')
|
133
|
+
else
|
134
|
+
get_es_resource('/_nodes/_local/stats/process')
|
135
|
+
end
|
136
|
+
begin
|
137
|
+
keys = stats['nodes'].keys
|
138
|
+
stats['nodes'][keys[0]]['process']['open_file_descriptors'].to_i
|
139
|
+
rescue NoMethodError
|
140
|
+
warning 'Failed to retrieve open_file_descriptors'
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def acquire_max_fds
|
145
|
+
info = if es_version < Gem::Version.new('2.0.0')
|
146
|
+
get_es_resource('/_nodes/_local?process=true')
|
147
|
+
elsif es_version < Gem::Version.new('5.0.0')
|
148
|
+
get_es_resource('/_nodes/_local/stats?process=true')
|
149
|
+
else
|
150
|
+
get_es_resource('/_nodes/_local/stats/process')
|
151
|
+
end
|
152
|
+
begin
|
153
|
+
keys = info['nodes'].keys
|
154
|
+
info['nodes'][keys[0]]['process']['max_file_descriptors'].to_i
|
155
|
+
rescue NoMethodError
|
156
|
+
warning 'Failed to retrieve max_file_descriptors'
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def run
|
161
|
+
open = acquire_open_fds
|
162
|
+
max = acquire_max_fds
|
163
|
+
used_percent = ((open.to_f / max.to_f) * 100).to_i
|
164
|
+
|
165
|
+
if used_percent >= config[:critical]
|
166
|
+
critical "fd usage #{used_percent}% exceeds #{config[:critical]}% (#{open}/#{max})"
|
167
|
+
elsif used_percent >= config[:warning]
|
168
|
+
warning "fd usage #{used_percent}% exceeds #{config[:warning]}% (#{open}/#{max})"
|
169
|
+
else
|
170
|
+
ok "fd usage at #{used_percent}% (#{open}/#{max})"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# check-es-heap
|
4
|
+
#
|
5
|
+
# DESCRIPTION:
|
6
|
+
# This plugin checks ElasticSearch's Java heap usage using its API.
|
7
|
+
#
|
8
|
+
# OUTPUT:
|
9
|
+
# plain text
|
10
|
+
#
|
11
|
+
# PLATFORMS:
|
12
|
+
# Linux
|
13
|
+
#
|
14
|
+
# DEPENDENCIES:
|
15
|
+
# gem: sensu-plugin
|
16
|
+
# gem: rest-client
|
17
|
+
#
|
18
|
+
# USAGE:
|
19
|
+
# example commands
|
20
|
+
#
|
21
|
+
# NOTES:
|
22
|
+
#
|
23
|
+
# LICENSE:
|
24
|
+
# Copyright 2012 Sonian, Inc <chefs@sonian.net>
|
25
|
+
# Released under the same terms as Sensu (the MIT license); see LICENSE
|
26
|
+
# for details.
|
27
|
+
#
|
28
|
+
|
29
|
+
require 'sensu-plugin/check/cli'
|
30
|
+
require 'rest-client'
|
31
|
+
require 'json'
|
32
|
+
require 'base64'
|
33
|
+
|
34
|
+
#
|
35
|
+
# ES Heap
|
36
|
+
#
|
37
|
+
class ESHeap < Sensu::Plugin::Check::CLI
|
38
|
+
option :host,
|
39
|
+
description: 'Elasticsearch host',
|
40
|
+
short: '-h HOST',
|
41
|
+
long: '--host HOST',
|
42
|
+
default: 'localhost'
|
43
|
+
|
44
|
+
option :port,
|
45
|
+
description: 'Elasticsearch port',
|
46
|
+
short: '-p PORT',
|
47
|
+
long: '--port PORT',
|
48
|
+
proc: proc(&:to_i),
|
49
|
+
default: 9200
|
50
|
+
|
51
|
+
option :warn,
|
52
|
+
short: '-w N',
|
53
|
+
long: '--warn N',
|
54
|
+
description: 'Heap used in bytes WARNING threshold',
|
55
|
+
proc: proc(&:to_i),
|
56
|
+
default: 0
|
57
|
+
|
58
|
+
option :timeout,
|
59
|
+
description: 'Sets the connection timeout for REST client',
|
60
|
+
short: '-t SECS',
|
61
|
+
long: '--timeout SECS',
|
62
|
+
proc: proc(&:to_i),
|
63
|
+
default: 30
|
64
|
+
|
65
|
+
option :crit,
|
66
|
+
short: '-c N',
|
67
|
+
long: '--crit N',
|
68
|
+
description: 'Heap used in bytes CRITICAL threshold',
|
69
|
+
proc: proc(&:to_i),
|
70
|
+
default: 0
|
71
|
+
|
72
|
+
option :percentage,
|
73
|
+
short: '-P',
|
74
|
+
long: '--percentage',
|
75
|
+
description: 'Use the WARNING and CRITICAL threshold numbers as percentage indicators of the total heap available',
|
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: '-W 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'
|
96
|
+
|
97
|
+
option :all,
|
98
|
+
description: 'Check all nodes in the ES cluster',
|
99
|
+
short: '-a',
|
100
|
+
long: '--all',
|
101
|
+
default: false
|
102
|
+
|
103
|
+
def acquire_es_version
|
104
|
+
info = acquire_es_resource('/')
|
105
|
+
info['version']['number']
|
106
|
+
end
|
107
|
+
|
108
|
+
def acquire_es_resource(resource)
|
109
|
+
headers = {}
|
110
|
+
if config[:user] && config[:password]
|
111
|
+
auth = 'Basic ' + Base64.strict_encode64("#{config[:user]}:#{config[:password]}").chomp
|
112
|
+
headers = { 'Authorization' => auth }
|
113
|
+
end
|
114
|
+
|
115
|
+
protocol = if config[:https]
|
116
|
+
'https'
|
117
|
+
else
|
118
|
+
'http'
|
119
|
+
end
|
120
|
+
|
121
|
+
r = if config[:cert_file]
|
122
|
+
RestClient::Resource.new("#{protocol}://#{config[:host]}:#{config[:port]}#{resource}",
|
123
|
+
ssl_ca_file: config[:cert_file].to_s,
|
124
|
+
timeout: config[:timeout],
|
125
|
+
headers: headers)
|
126
|
+
else
|
127
|
+
RestClient::Resource.new("#{protocol}://#{config[:host]}:#{config[:port]}#{resource}",
|
128
|
+
timeout: config[:timeout],
|
129
|
+
headers: headers)
|
130
|
+
end
|
131
|
+
JSON.parse(r.get)
|
132
|
+
rescue Errno::ECONNREFUSED
|
133
|
+
warning 'Connection refused'
|
134
|
+
rescue RestClient::RequestTimeout
|
135
|
+
warning 'Connection timed out'
|
136
|
+
rescue RestClient::ServiceUnavailable
|
137
|
+
warning 'Service is unavailable'
|
138
|
+
rescue JSON::ParserError
|
139
|
+
warning 'Elasticsearch API returned invalid JSON'
|
140
|
+
end
|
141
|
+
|
142
|
+
def acquire_stats
|
143
|
+
if Gem::Version.new(acquire_es_version) >= Gem::Version.new('1.0.0')
|
144
|
+
if config[:all]
|
145
|
+
acquire_es_resource('/_nodes/stats')
|
146
|
+
else
|
147
|
+
acquire_es_resource('/_nodes/_local/stats')
|
148
|
+
end
|
149
|
+
elsif config[:all]
|
150
|
+
acquire_es_resource('/_cluster/nodes/stats')
|
151
|
+
else
|
152
|
+
acquire_es_resource('/_cluster/nodes/_local/stats')
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def acquire_heap_data(node)
|
157
|
+
return node['jvm']['mem']['heap_used_in_bytes'], node['jvm']['mem']['heap_max_in_bytes']
|
158
|
+
rescue StandardError
|
159
|
+
warning 'Failed to obtain heap used in bytes'
|
160
|
+
end
|
161
|
+
|
162
|
+
def acquire_heap_usage(heap_used, heap_max, node_name)
|
163
|
+
if config[:percentage]
|
164
|
+
heap_usage = ((100 * heap_used) / heap_max).to_i
|
165
|
+
output = if config[:all]
|
166
|
+
"Node #{node_name}: Heap used in bytes #{heap_used} (#{heap_usage}% full)\n"
|
167
|
+
else
|
168
|
+
"Heap used in bytes #{heap_used} (#{heap_usage}% full)"
|
169
|
+
end
|
170
|
+
else
|
171
|
+
heap_usage = heap_used
|
172
|
+
output = config[:all] ? "Node #{node_name}: Heap used in bytes #{heap_used}\n" : "Heap used in bytes #{heap_used}"
|
173
|
+
end
|
174
|
+
[heap_usage, output]
|
175
|
+
end
|
176
|
+
|
177
|
+
def run
|
178
|
+
stats = acquire_stats
|
179
|
+
status = { crit: '', warn: '', ok: '' }
|
180
|
+
|
181
|
+
# Check all the nodes in the cluster, alert if any of the nodes have heap usage above thresholds
|
182
|
+
stats['nodes'].each_value do |node|
|
183
|
+
heap_used, heap_max = acquire_heap_data(node)
|
184
|
+
heap_usage, output = acquire_heap_usage(heap_used, heap_max, node['name'])
|
185
|
+
if heap_usage >= config[:crit]
|
186
|
+
status[:crit] += output
|
187
|
+
elsif heap_usage >= config[:warn]
|
188
|
+
status[:warn] += output
|
189
|
+
elsif !config[:all]
|
190
|
+
status[:ok] += output
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
if !status[:crit].empty?
|
195
|
+
message status[:crit]
|
196
|
+
critical
|
197
|
+
elsif !status[:warn].empty?
|
198
|
+
message status[:warn]
|
199
|
+
warning
|
200
|
+
else
|
201
|
+
message status[:ok]
|
202
|
+
ok
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Check Elastic Search Indexes
|
4
|
+
# ===
|
5
|
+
#
|
6
|
+
# DESCRIPTION:
|
7
|
+
# This plugin will check a a node for dupe indexes
|
8
|
+
#
|
9
|
+
# OUTPUT:
|
10
|
+
# plain-text
|
11
|
+
#
|
12
|
+
# PLATFORMS:
|
13
|
+
# Linux
|
14
|
+
#
|
15
|
+
# DEPENDENCIES:
|
16
|
+
# gem: sensu-plugin
|
17
|
+
#
|
18
|
+
# needs usage
|
19
|
+
# USAGE:
|
20
|
+
#
|
21
|
+
# NOTES:
|
22
|
+
#
|
23
|
+
# LICENSE:
|
24
|
+
# Copyright 2014 Yieldbot, Inc <devops@yieldbot.com>
|
25
|
+
# Released under the same terms as Sensu (the MIT license); see LICENSE
|
26
|
+
# for details.
|
27
|
+
#
|
28
|
+
|
29
|
+
require 'sensu-plugin/check/cli'
|
30
|
+
|
31
|
+
#
|
32
|
+
# == Check Elastic Search Cluster Index
|
33
|
+
#
|
34
|
+
class CheckESClusterIndex < Sensu::Plugin::Check::CLI
|
35
|
+
option :cluster,
|
36
|
+
description: 'Array of clusters to check',
|
37
|
+
short: '-C CLUSTER[,CLUSTER]',
|
38
|
+
long: '--cluster CLUSTER[,CLUSTER]',
|
39
|
+
proc: proc { |a| a.split(',') }
|
40
|
+
|
41
|
+
option :ignore,
|
42
|
+
description: 'Comma separated list of indexes to ignore',
|
43
|
+
short: '-i INDEX[,INDEX]',
|
44
|
+
long: '--ignore INDEX[,INDEX]',
|
45
|
+
proc: proc { |a| a.split(',') }
|
46
|
+
|
47
|
+
option :debug,
|
48
|
+
description: 'Debug',
|
49
|
+
short: '-d',
|
50
|
+
long: '--debug'
|
51
|
+
|
52
|
+
def run
|
53
|
+
# If only one cluster is given, no need to check the indexes
|
54
|
+
ok 'All indexes are unique' if config[:cluster].length == 1
|
55
|
+
|
56
|
+
port = ':9200'
|
57
|
+
cmd = '/_cat/indices?v | tail -n +2'
|
58
|
+
|
59
|
+
valid_index = {}
|
60
|
+
dupe_index = {}
|
61
|
+
config[:cluster].each do |u|
|
62
|
+
index_arr = `curl -s #{ u }#{ port }#{ cmd }`.split("\n")
|
63
|
+
index_arr.each do |t|
|
64
|
+
t = t.split[1]
|
65
|
+
|
66
|
+
# If the index is in the ignore list, go to the next one
|
67
|
+
next if config[:ignore].include? t
|
68
|
+
|
69
|
+
if valid_index.key?(t)
|
70
|
+
dupe_index[t] = [] unless dupe_index[t].is_a?(Array)
|
71
|
+
dupe_index[t] << u
|
72
|
+
dupe_index[t] << valid_index[t] unless dupe_index[t]
|
73
|
+
.include?(valid_index[t])
|
74
|
+
else
|
75
|
+
valid_index[t] = [] unless valid_index[t].is_a?(Array)
|
76
|
+
valid_index[t] << u
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
if dupe_index.count > 0
|
82
|
+
dupe_index.each do |k, v|
|
83
|
+
critical "#{k} is on #{v}"
|
84
|
+
end
|
85
|
+
else
|
86
|
+
ok 'All indexes are unique'
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|