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