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