sensu-plugins-graphite-boutetnico 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fd8d8fbe966a0e73b730fa0961d3423480e373ba
4
+ data.tar.gz: 5a1422843684c036eae71271d75ef05cfc12f7eb
5
+ SHA512:
6
+ metadata.gz: d74a7d26e63630e9ed672326f00fc78a51a80ac2ea93ec79b111f676507d4df277988400aa36e472be4e383087c2e9524fd902d51dce4bf79225eed1a81288ad
7
+ data.tar.gz: 5daef99682f10d636733961318dea35485444a6e6b960157bed488ddce1f084f3e0b279f0fb8d8dfe674759ac4e6b585ef23aedc3ad41c321eaad1050c1dbf29
@@ -0,0 +1 @@
1
+ Can be found at [https://github.com/boutetnico/sensu-plugins-graphite/releases](https://github.com/boutetnico/sensu-plugins-graphite/releases).
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Sensu-Plugins
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,126 @@
1
+ ## Sensu-Plugins-graphite
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/sensu-plugins-graphite-boutetnico.svg)](https://badge.fury.io/rb/sensu-plugins-graphite-boutetnico.svg)
4
+ [![Sensu Bonsai Asset](https://img.shields.io/badge/Bonsai-Download%20Me-brightgreen.svg?colorB=89C967&logo=sensu)](https://bonsai.sensu.io/assets/boutetnico/sensu-plugins-graphite)
5
+
6
+ ## This is an unofficial fork
7
+
8
+ This fork is automatically tested, built and published to [RubyGems](https://rubygems.org/gems/sensu-plugins-graphite-boutetnico/) and [Bonsai](https://bonsai.sensu.io/assets/boutetnico/sensu-plugins-graphite).
9
+
10
+ ## Files
11
+ * bin/check-graphite-data
12
+ * bin/check-graphite-replication
13
+ * bin/check-graphite-stats
14
+ * bin/check-graphite
15
+ * bin/extension-graphite
16
+ * bin/handler-graphite-event
17
+ * bin/handler-graphite-notify
18
+ * bin/handler-graphite-status
19
+ * bin/handler-graphite-occurrences
20
+ * bin/mutator-graphite
21
+
22
+ ## Usage
23
+
24
+ ### handler-graphite-event
25
+ ```
26
+ {
27
+ "graphite_event": {
28
+ "server_uri": "https://graphite.example.com:443/events/",
29
+ "tags": [
30
+ "custom_tag_a",
31
+ "custom_tag_b"
32
+ ]
33
+ }
34
+ }
35
+ ```
36
+
37
+ ### handler-graphite-occurrences
38
+ ```
39
+ {
40
+ "graphite": {
41
+ "server":"graphite.example.com",
42
+ "port":"2003"
43
+ }
44
+ }
45
+ ```
46
+
47
+ ### handler-graphite-notify
48
+ ```
49
+ {
50
+ "graphite_notify": {
51
+ "host":"graphite.example.com",
52
+ "port":"2003",
53
+ "prefix":"sensu.events"
54
+ }
55
+ }
56
+ ```
57
+
58
+ ### handler-graphite-status
59
+ ```
60
+ {
61
+ "graphite_status": {
62
+ "host":"graphite.example.com",
63
+ "port":"2003",
64
+ "prefix":"sensu.events"
65
+ }
66
+ }
67
+ ```
68
+
69
+ ## Full Configuration Example
70
+ +**Note that TCP Handler is preferred**
71
+ ```
72
+ {
73
+ "graphite_event": {
74
+ "server_uri": "https://graphite.example.com:443/events/",
75
+ "tags": [
76
+ "custom_tag_a",
77
+ "custom_tag_b"
78
+ ]
79
+ },
80
+ "handlers":
81
+ {
82
+ "default": {
83
+ "type": "set",
84
+ "handlers": [
85
+ "graphite_event"
86
+ ]
87
+ },
88
+ "graphite_tcp": {
89
+ "type": "tcp",
90
+ "socket": {
91
+ "host":"graphite.example.com",
92
+ "port":2003
93
+ },
94
+ "mutator": "only_check_output"
95
+ },
96
+ "graphite_event": {
97
+ "type": "pipe",
98
+ "filters": [
99
+ "custom_filter_a",
100
+ "custom_filter_b"
101
+ ],
102
+ "command": "handler-graphite-event.rb"
103
+ }
104
+ },
105
+ "checks": {
106
+ "metrics_uptime": {
107
+ "standalone": true,
108
+ "type": "metric",
109
+ "handlers": [
110
+ "graphite_tcp"
111
+ ],
112
+ "interval": 60,
113
+ "command": "metrics-uptime.rb --scheme sensu.host.$(hostname).uptime",
114
+ "subscribers": [
115
+ "core"
116
+ ]
117
+ }
118
+ }
119
+ }
120
+ ```
121
+
122
+ ## Installation
123
+
124
+ [Installation and Setup](http://sensu-plugins.io/docs/installation_instructions.html)
125
+
126
+ ## Notes
@@ -0,0 +1,115 @@
1
+ #! /usr/bin/env ruby
2
+ #
3
+ # check-data
4
+ #
5
+ # DESCRIPTION:
6
+ # This plugin checks values within graphite
7
+ #
8
+ # OUTPUT:
9
+ # plain text
10
+ #
11
+ # PLATFORMS:
12
+ # Linux
13
+ #
14
+ # DEPENDENCIES:
15
+ # gem: sensu-plugin
16
+ #
17
+ # USAGE:
18
+ # #YELLOW
19
+ #
20
+ # NOTES:
21
+ #
22
+ # LICENSE:
23
+ # Copyright 2014 Sonian, Inc. and contributors. <support@sensuapp.org>
24
+ # Released under the same terms as Sensu (the MIT license); see LICENSE
25
+ # for details.
26
+ #
27
+
28
+ require 'sensu-plugin/check/cli'
29
+ require 'json'
30
+ require 'open-uri'
31
+ require 'openssl'
32
+
33
+ require 'sensu-plugins-graphite/graphite_proxy/options'
34
+ require 'sensu-plugins-graphite/graphite_proxy/proxy'
35
+
36
+ class CheckGraphiteData < Sensu::Plugin::Check::CLI
37
+ include SensuPluginsGraphite::GraphiteProxy::Options
38
+
39
+ option :reset_on_decrease,
40
+ description: 'Send OK if value has decreased on any values within END-INTERVAL to END',
41
+ short: '-r INTERVAL',
42
+ long: '--reset INTERVAL',
43
+ proc: proc(&:to_i)
44
+
45
+ option :allowed_graphite_age,
46
+ description: 'Allowed number of seconds since last data update (default: 60 seconds)',
47
+ short: '-a SECONDS',
48
+ long: '--age SECONDS',
49
+ default: 60,
50
+ proc: proc(&:to_i)
51
+
52
+ # Run checks
53
+ def run
54
+ if config[:help]
55
+ puts opt_parser if config[:help]
56
+ exit
57
+ end
58
+
59
+ proxy = SensuPluginsGraphite::GraphiteProxy::Proxy.new(config)
60
+ begin
61
+ results = proxy.retrieve_data!
62
+ results.each_pair do |_key, value|
63
+ @value = value
64
+ @data = value['data']
65
+ check_age || check(:critical) || check(:warning)
66
+ end
67
+
68
+ ok("#{name} value OK")
69
+ rescue SensuPluginsGraphite::GraphiteProxy::ProxyError => e
70
+ unknown e.message
71
+ end
72
+ end
73
+
74
+ # name used in responses
75
+ def name
76
+ base = config[:name]
77
+ @formatted ? "#{base} (#{@formatted})" : base
78
+ end
79
+
80
+ # Check the age of the data being processed
81
+ def check_age
82
+ if (Time.now.to_i - @value['end']) > config[:allowed_graphite_age]
83
+ unknown "Graphite data age is past allowed threshold (#{config[:allowed_graphite_age]} seconds)"
84
+ end
85
+ end
86
+
87
+ # type:: :warning or :critical
88
+ # Return alert if required
89
+ def check(type)
90
+ if config[type]
91
+ send(type, "#{@value['target']} has passed #{type} threshold (#{@data.last})") if below?(type) || above?(type)
92
+ end
93
+ end
94
+
95
+ # Check if value is below defined threshold
96
+ def below?(type)
97
+ config[:below] && @data.last < config[type]
98
+ end
99
+
100
+ # Check is value is above defined threshold
101
+ def above?(type)
102
+ !config[:below] && (@data.last > config[type]) && !decreased?
103
+ end
104
+
105
+ # Check if values have decreased within interval if given
106
+ def decreased?
107
+ if config[:reset_on_decrease]
108
+ slice = @data.slice(@data.size - config[:reset_on_decrease], @data.size)
109
+ val = slice.shift until slice.empty? || val.to_f > slice.first
110
+ !slice.empty?
111
+ else
112
+ false
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,97 @@
1
+ #! /usr/bin/env ruby
2
+ #
3
+ # check-graphite-hosts
4
+ #
5
+ # DESCRIPTION:
6
+ # This plugin checks the number of hosts within Graphite that are sending
7
+ # data, and alerts if it is below a given threshold
8
+ #
9
+ # OUTPUT:
10
+ # plain text
11
+ #
12
+ # PLATFORMS:
13
+ # Linux
14
+ #
15
+ # DEPENDENCIES:
16
+ # gem: sensu-plugin
17
+ #
18
+ # USAGE:
19
+ # #YELLOW
20
+ #
21
+ # NOTES:
22
+ #
23
+ # LICENSE:
24
+ # Copyright 2014 Sonian, Inc. and contributors. <support@sensuapp.org>
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 'json'
31
+ require 'open-uri'
32
+ require 'openssl'
33
+
34
+ require 'sensu-plugins-graphite/graphite_proxy/options'
35
+ require 'sensu-plugins-graphite/graphite_proxy/proxy'
36
+
37
+ class CheckGraphiteHosts < Sensu::Plugin::Check::CLI
38
+ include SensuPluginsGraphite::GraphiteProxy::Options
39
+
40
+ # Run checks
41
+ def run
42
+ if config[:help]
43
+ puts opt_parser if config[:help]
44
+ exit
45
+ end
46
+
47
+ proxy = SensuPluginsGraphite::GraphiteProxy::Proxy.new(config)
48
+ begin
49
+ results = proxy.retrieve_data!
50
+
51
+ check(:critical, results) || check(:warning, results)
52
+ ok("#{name} value (#{hosts_with_data(results)}) OK")
53
+ rescue SensuPluginsGraphite::GraphiteProxy::ProxyError => e
54
+ unknown e.message
55
+ end
56
+ end
57
+
58
+ # name used in responses
59
+ def name
60
+ base = config[:name]
61
+ @formatted ? "#{base} (#{@formatted})" : base
62
+ end
63
+
64
+ # return the number of hosts with data in the given set of results
65
+ def hosts_with_data(resultset)
66
+ resultset.count { |_host, values| !values['data'].empty? }
67
+ end
68
+
69
+ # type:: :warning or :critical
70
+ # Return alert if required
71
+ def check(type, results)
72
+ # #YELLOW
73
+ num_hosts = hosts_with_data(results)
74
+ return unless config[type] && threshold_crossed?(type, num_hosts)
75
+
76
+ msg = hosts_threshold_message(config[:target], num_hosts, type)
77
+ send(type, msg)
78
+ end
79
+
80
+ def threshold_crossed?(type, num_hosts)
81
+ below?(type, num_hosts) || above?(type, num_hosts)
82
+ end
83
+
84
+ def hosts_threshold_message(target, hosts, type)
85
+ "Number of hosts sending #{target} (#{hosts}) has passed #{type} threshold (#{config[type]})"
86
+ end
87
+
88
+ # Check if value is below defined threshold
89
+ def below?(type, val)
90
+ config[:below] && val < config[type]
91
+ end
92
+
93
+ # Check is value is above defined threshold
94
+ def above?(type, val)
95
+ !config[:below] && (val > config[type])
96
+ end
97
+ end
@@ -0,0 +1,234 @@
1
+ #! /usr/bin/env ruby
2
+ #
3
+ # check-replication
4
+ #
5
+ # DESCRIPTION:
6
+ # Check to ensure data gets posted and is retrievable by Graphite.
7
+ # We post to each server in config[:relays] then sleep config[:sleep]
8
+ # seconds then check each of config[:graphites] to see if the data made it
9
+ # to each one. OK if all servers have the data we expected, WARN if
10
+ # config[:warning] or fewer have it. CRITICAL if config[:critical]
11
+ # or fewer have it. config[:check_id] allows you to have many of these
12
+ # checks running in different places without any conflicts. Customize it
13
+ # if you are going to run this check from multiple servers. Otherwise
14
+ # it defaults to default. (can be a descriptive string, used as a Graphite key)
15
+ #
16
+ # This check is most useful when you have a cluster of carbon-relays configured
17
+ # with REPLICATION_FACTOR > 1 and more than one Graphite server those
18
+ # carbon-relays are configured to post to. This check ensures that replication
19
+ # is actually happening in a timely manner.
20
+ #
21
+ # How it works: We generate a large random number for each of these servers
22
+ # Then we post that number to each server via a key in the form of:
23
+ # checks.graphite.check_id.replication.your_graphite_server.ip It's safe
24
+ # to throw this data away quickly. A day retention ought to be more
25
+ # than enough for anybody.
26
+ #
27
+ # OUTPUT:
28
+ # plain text
29
+ #
30
+ # PLATFORMS:
31
+ # Linux
32
+ #
33
+ # DEPENDENCIES:
34
+ # gem: sensu-plugin
35
+ # gem: rest-client
36
+ # gem: ipaddress
37
+ #
38
+ # USAGE:
39
+ # Basic check, expect metrics to land on these graphite servers
40
+ # check-graphite-replication.rb -r relay1 -g graphite1,graphite2
41
+ #
42
+ # Make sure all 4 graphite instances get the metric
43
+ # check-graphite-replication.rb -r relay1 -g graphite1,graphite2,graphite3 graphite4 -c 1
44
+ #
45
+ # Test multiple relay servers
46
+ # check-graphite-replication.rb -r relay1,relay2 -g graphite1,graphite2
47
+ #
48
+ # Test from multiple locations (no conflicts)
49
+ # check-graphite-replication.rb -r relay1,relay2 -g graphite1,graphite2 -i check_1
50
+ # check-graphite-replication.rb -r relay1,relay2 -g graphite1,graphite2 -i check_2
51
+ #
52
+ # LICENSE:
53
+ # AJ Bourg <aj@ajbourg.com>
54
+ # Released under the same terms as Sensu (the MIT license); see LICENSE
55
+ # for details.
56
+ #
57
+
58
+ require 'sensu-plugin/check/cli'
59
+ require 'timeout'
60
+ require 'socket'
61
+ require 'rest-client'
62
+ require 'json'
63
+ require 'resolv'
64
+ require 'ipaddress'
65
+
66
+ class CheckGraphiteReplication < Sensu::Plugin::Check::CLI
67
+ option :relays,
68
+ short: '-r RELAYS',
69
+ long: '--relays RELAYS',
70
+ description: 'Comma separated list of Carbon relay servers to post to.',
71
+ required: true
72
+ option :servers,
73
+ short: '-g SERVERS',
74
+ long: '--graphite SERVERS',
75
+ description: 'Comma separated list of all Graphite servers to check.',
76
+ required: true
77
+ option :sleep,
78
+ short: '-s SECONDS',
79
+ long: '--sleep SECONDS',
80
+ description: 'Time to sleep between submitting and checking for value.',
81
+ default: 30,
82
+ proc: proc(&:to_i)
83
+ option :timeout,
84
+ short: '-t TIMEOUT',
85
+ long: '--timeout TIMEOUT',
86
+ description: 'Timeout limit for posting to the relay.',
87
+ default: 5,
88
+ proc: proc(&:to_i)
89
+ option :port,
90
+ short: '-p PORT',
91
+ long: '--port PORT',
92
+ description: 'Port to post to carbon-relay on.',
93
+ default: 2003,
94
+ proc: proc(&:to_i)
95
+ option :critical,
96
+ short: '-c COUNT',
97
+ long: '--critical COUNT',
98
+ description: 'Number of servers missing our test data to be critical.',
99
+ default: 2,
100
+ proc: proc(&:to_i)
101
+ option :warning,
102
+ short: '-w COUNT',
103
+ long: '--warning COUNT',
104
+ description: 'Number of servers missing our test data to be warning.',
105
+ default: 1,
106
+ proc: proc(&:to_i)
107
+ option :check_id,
108
+ short: '-i ID',
109
+ long: '--check-id ID',
110
+ description: 'Check ID to identify this check.',
111
+ default: 'default'
112
+ option :verbose,
113
+ short: '-v',
114
+ long: '--verbose',
115
+ description: 'Verbose.',
116
+ default: false,
117
+ boolean: true
118
+
119
+ def run
120
+ messages = []
121
+ servers = config[:servers].split(',')
122
+ relay_ips = find_relay_ips(config[:relays].split(','))
123
+
124
+ check_id = graphite_key(config[:check_id])
125
+
126
+ relay_ips.each do |server_name, ips|
127
+ ips.each do |ip|
128
+ messages << post_message(server_name, ip, check_id)
129
+ end
130
+ end
131
+
132
+ puts "Sleeping for #{config[:sleep]}." if config[:verbose]
133
+ sleep(config[:sleep])
134
+
135
+ fail_count = 0
136
+ # on every server, check to see if all our data replicated
137
+ servers.each do |server|
138
+ messages.each do |c|
139
+ unless check_for_message(server, c['key'], c['value'])
140
+ puts "#{c['relay']} (#{c['ip']}) didn't post to #{server}"
141
+ fail_count += 1
142
+ end
143
+ end
144
+ end
145
+
146
+ if fail_count >= config[:critical]
147
+ critical "Missing data points. #{fail_count} lookups failed."
148
+ elsif fail_count >= config[:warning]
149
+ warning "Missing data points. #{fail_count} lookups failed."
150
+ end
151
+
152
+ success_count = (messages.length * servers.length) - fail_count
153
+ ok "#{fail_count} failed checks. #{success_count} successful checks."
154
+ end
155
+
156
+ def find_relay_ips(relays)
157
+ # we may have gotten an IPAddress or a DNS hostname or a mix, so let's try
158
+
159
+ relay_ips = {}
160
+
161
+ time_out('resolving DNS') do
162
+ relays.each do |r|
163
+ relay_ips[r] = if IPAddress.valid? r
164
+ [r]
165
+ else
166
+ Resolv.getaddresses(r)
167
+ end
168
+ end
169
+ end
170
+
171
+ relay_ips
172
+ end
173
+
174
+ def post_message(server_name, ip, check_id)
175
+ server_key = graphite_key(server_name)
176
+
177
+ number = rand(10_000)
178
+ time = Time.now.to_i
179
+
180
+ ip_key = graphite_key(ip)
181
+ key = "checks.graphite.#{check_id}.replication.#{server_key}.#{ip_key}"
182
+
183
+ time_out("posting data to #{ip}") do
184
+ t = TCPSocket.new(ip, config[:port])
185
+ t.puts("#{key} #{number} #{time}")
186
+ t.close
187
+ end
188
+
189
+ if config[:verbose]
190
+ puts "Posted #{key} to #{server_name} with #{number} on IP #{ip}."
191
+ end
192
+
193
+ { 'relay' => server_name, 'ip' => ip, 'key' => key, 'value' => number }
194
+ end
195
+
196
+ # checks to see if a value landed on a graphite server
197
+ def check_for_message(server, key, value)
198
+ url = "http://#{server}/render?format=json&target=#{key}&from=-10minutes"
199
+
200
+ puts "Checking URL #{url}" if config[:verbose]
201
+ graphite_data = nil
202
+
203
+ begin
204
+ time_out("querying Graphite API on #{server}") do
205
+ graphite_data = RestClient.get url
206
+ graphite_data = JSON.parse(graphite_data)
207
+ end
208
+ rescue RestClient::Exception, JSON::ParserError => e
209
+ critical "Unexpected error getting data from #{server}: #{e}"
210
+ end
211
+
212
+ success = false
213
+
214
+ # we get all the data points for the last 10 minutes, so see if our value
215
+ # appeared in any of them
216
+ graphite_data[0]['datapoints'].each do |v|
217
+ success = true if v[0] == value
218
+ end
219
+
220
+ success
221
+ end
222
+
223
+ def graphite_key(key)
224
+ key.tr(',', '_').tr(' ', '_').tr('.', '_').tr('-', '_')
225
+ end
226
+
227
+ def time_out(activity, &block)
228
+ Timeout.timeout(config[:timeout]) do
229
+ yield block
230
+ end
231
+ rescue Timeout::Error
232
+ critical "Timed out while #{activity}"
233
+ end
234
+ end