sensu-plugins-consul-magec 2.2.1
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 +161 -0
- data/LICENSE +22 -0
- data/README.md +29 -0
- data/bin/check-consul-failures.rb +103 -0
- data/bin/check-consul-kv-ttl.rb +176 -0
- data/bin/check-consul-leader.rb +129 -0
- data/bin/check-consul-maintenance.rb +98 -0
- data/bin/check-consul-members.rb +136 -0
- data/bin/check-consul-quorum.rb +91 -0
- data/bin/check-consul-servers.rb +118 -0
- data/bin/check-consul-service-health.rb +161 -0
- data/bin/check-consul-stale-peers.rb +73 -0
- data/bin/check-service-consul.rb +160 -0
- data/lib/sensu-plugins-consul.rb +3 -0
- data/lib/sensu-plugins-consul/check/base.rb +112 -0
- data/lib/sensu-plugins-consul/version.rb +11 -0
- metadata +246 -0
@@ -0,0 +1,118 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# check-consul-servers
|
6
|
+
#
|
7
|
+
# DESCRIPTION:
|
8
|
+
# This plugin checks if consul is up and reachable. It then checks
|
9
|
+
# the number of peers matches the excepted value
|
10
|
+
#
|
11
|
+
# OUTPUT:
|
12
|
+
# plain text
|
13
|
+
#
|
14
|
+
# PLATFORMS:
|
15
|
+
# Linux
|
16
|
+
#
|
17
|
+
# DEPENDENCIES:
|
18
|
+
# gem: sensu-plugin
|
19
|
+
# gem: diplomat
|
20
|
+
#
|
21
|
+
# USAGE:
|
22
|
+
# #YELLOW
|
23
|
+
#
|
24
|
+
# NOTES:
|
25
|
+
#
|
26
|
+
# LICENSE:
|
27
|
+
# Copyright 2015 Sonian, Inc. and contributors. <support@sensuapp.org>
|
28
|
+
# Released under the same terms as Sensu (the MIT license); see LICENSE
|
29
|
+
# for details.
|
30
|
+
#
|
31
|
+
|
32
|
+
require 'sensu-plugin/check/cli'
|
33
|
+
require 'rest-client'
|
34
|
+
require 'json'
|
35
|
+
|
36
|
+
#
|
37
|
+
# Consul Status
|
38
|
+
#
|
39
|
+
class ConsulStatus < Sensu::Plugin::Check::CLI
|
40
|
+
option :server,
|
41
|
+
description: 'consul server',
|
42
|
+
short: '-s SERVER',
|
43
|
+
long: '--server SERVER',
|
44
|
+
default: '127.0.0.1'
|
45
|
+
|
46
|
+
option :port,
|
47
|
+
description: 'consul http port',
|
48
|
+
short: '-p PORT',
|
49
|
+
long: '--port PORT',
|
50
|
+
default: '8500'
|
51
|
+
|
52
|
+
option :min,
|
53
|
+
description: 'minimum number of peers',
|
54
|
+
short: '-g GREATER THAN',
|
55
|
+
long: '--greater GREATER THAN',
|
56
|
+
proc: proc(&:to_i),
|
57
|
+
default: 3
|
58
|
+
|
59
|
+
option :expected,
|
60
|
+
description: 'expected number of peers',
|
61
|
+
short: '-e EXPECT',
|
62
|
+
long: '--expect EXPECT',
|
63
|
+
proc: proc(&:to_i),
|
64
|
+
default: 5
|
65
|
+
|
66
|
+
option :scheme,
|
67
|
+
description: 'consul listener scheme',
|
68
|
+
short: '-S SCHEME',
|
69
|
+
long: '--scheme SCHEME',
|
70
|
+
default: 'http'
|
71
|
+
|
72
|
+
option :insecure,
|
73
|
+
description: 'if set, disables SSL verification',
|
74
|
+
short: '-k',
|
75
|
+
long: '--insecure',
|
76
|
+
boolean: true,
|
77
|
+
default: false
|
78
|
+
|
79
|
+
option :capath,
|
80
|
+
description: 'absolute path to an alternate CA file',
|
81
|
+
short: '-c CAPATH',
|
82
|
+
long: '--capath CAPATH'
|
83
|
+
|
84
|
+
option :timeout,
|
85
|
+
description: 'connection will time out after this many seconds',
|
86
|
+
short: '-t TIMEOUT_IN_SECONDS',
|
87
|
+
long: '--timeout TIMEOUT_IN_SECONDS',
|
88
|
+
proc: proc(&:to_i),
|
89
|
+
default: 5
|
90
|
+
|
91
|
+
option :token,
|
92
|
+
description: 'ACL token',
|
93
|
+
long: '--token ACL_TOKEN'
|
94
|
+
|
95
|
+
def run
|
96
|
+
url = "#{config[:scheme]}://#{config[:server]}:#{config[:port]}/v1/status/peers"
|
97
|
+
options = { timeout: config[:timeout],
|
98
|
+
verify_ssl: (OpenSSL::SSL::VERIFY_NONE if defined? config[:insecure]),
|
99
|
+
ssl_ca_file: (config[:capath] if defined? config[:capath]),
|
100
|
+
headers: { 'X-Consul-Token' => config[:token] } }
|
101
|
+
|
102
|
+
json = RestClient::Resource.new(url, options).get
|
103
|
+
peers = JSON.parse(json).length.to_i
|
104
|
+
if peers < config[:min]
|
105
|
+
critical "[#{peers}] peers is below critical threshold of [#{config[:min]}]"
|
106
|
+
elsif peers != config[:expected]
|
107
|
+
warning "[#{peers}] peers is outside of expected count of [#{config[:expected]}]"
|
108
|
+
else
|
109
|
+
ok 'Peers within threshold'
|
110
|
+
end
|
111
|
+
rescue Errno::ECONNREFUSED
|
112
|
+
critical 'Consul is not responding'
|
113
|
+
rescue RestClient::RequestTimeout
|
114
|
+
critical 'Consul Connection timed out'
|
115
|
+
rescue RestClient::Exception => e
|
116
|
+
unknown "Consul returned: #{e}"
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# check-consul-service-health
|
6
|
+
#
|
7
|
+
# DESCRIPTION:
|
8
|
+
# This plugin assists in checking the check status of a Consul Service
|
9
|
+
# In addition, it provides additional Yieldbot logic for Output containing
|
10
|
+
# JSON.
|
11
|
+
#
|
12
|
+
# OUTPUT:
|
13
|
+
# plain text
|
14
|
+
#
|
15
|
+
# PLATFORMS:
|
16
|
+
# Linux
|
17
|
+
#
|
18
|
+
# DEPENDENCIES:
|
19
|
+
# gem: sensu-plugin
|
20
|
+
# gem: diplomat
|
21
|
+
#
|
22
|
+
# USAGE:
|
23
|
+
# ./check-consul-service-health -s influxdb
|
24
|
+
# ./check-consul-service-health -a
|
25
|
+
#
|
26
|
+
# NOTES:
|
27
|
+
#
|
28
|
+
# LICENSE:
|
29
|
+
# Copyright 2015 Yieldbot, Inc. <devops@yieldbot.com>
|
30
|
+
# Released under the same terms as Sensu (the MIT license); see LICENSE
|
31
|
+
# for details.
|
32
|
+
#
|
33
|
+
|
34
|
+
require 'sensu-plugin/check/cli'
|
35
|
+
require 'diplomat'
|
36
|
+
require 'json'
|
37
|
+
|
38
|
+
#
|
39
|
+
# Service Status
|
40
|
+
#
|
41
|
+
class CheckConsulServiceHealth < Sensu::Plugin::Check::CLI
|
42
|
+
option :consul,
|
43
|
+
description: 'consul server',
|
44
|
+
long: '--consul SERVER',
|
45
|
+
default: 'http://localhost:8500'
|
46
|
+
|
47
|
+
option :nodename,
|
48
|
+
description: 'check all consul services running on the specified node',
|
49
|
+
short: '-n NODENAME',
|
50
|
+
long: '--node NODENAME'
|
51
|
+
|
52
|
+
option :service,
|
53
|
+
description: 'a service managed by consul',
|
54
|
+
short: '-s SERVICE',
|
55
|
+
long: '--service SERVICE',
|
56
|
+
default: 'consul'
|
57
|
+
|
58
|
+
option :tags,
|
59
|
+
description: 'filter services by a comma-separated list of tags (requires --service)',
|
60
|
+
short: '-t TAGS',
|
61
|
+
long: '--tags TAGS'
|
62
|
+
|
63
|
+
option :all,
|
64
|
+
description: 'get all services (not compatible with --tags)',
|
65
|
+
short: '-a',
|
66
|
+
long: '--all'
|
67
|
+
|
68
|
+
option :fail_if_not_found,
|
69
|
+
description: 'fail if no service is found',
|
70
|
+
short: '-f',
|
71
|
+
long: '--fail-if-not-found'
|
72
|
+
|
73
|
+
option :token,
|
74
|
+
description: 'ACL token',
|
75
|
+
long: '--token ACL_TOKEN'
|
76
|
+
|
77
|
+
# Get the service checks for the given service
|
78
|
+
def acquire_service_data
|
79
|
+
if config[:tags] && config[:service]
|
80
|
+
tags = config[:tags].split(',').to_set
|
81
|
+
services = []
|
82
|
+
Diplomat::Health.service(config[:service]).each do |s|
|
83
|
+
if s['Service']['Tags'].to_set.superset? tags
|
84
|
+
services.push(*s['Checks'])
|
85
|
+
end
|
86
|
+
end
|
87
|
+
services
|
88
|
+
elsif config[:nodename]
|
89
|
+
data = []
|
90
|
+
begin
|
91
|
+
services = Diplomat::Node.get(config[:nodename]).Services
|
92
|
+
rescue StandardError
|
93
|
+
services = {}
|
94
|
+
end
|
95
|
+
services.each_value do |service|
|
96
|
+
Diplomat::Health.checks(service['Service']).each do |check|
|
97
|
+
data.push(check) if check.Node == config[:nodename]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
data
|
101
|
+
elsif config[:all]
|
102
|
+
Diplomat::Health.state('any')
|
103
|
+
else
|
104
|
+
Diplomat::Health.checks(config[:service])
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Do work
|
109
|
+
def run
|
110
|
+
if config[:tags] && config[:all]
|
111
|
+
critical 'Cannot specify --tags and --all simultaneously (Consul health/service/ versus health/state/).'
|
112
|
+
end
|
113
|
+
|
114
|
+
Diplomat.configure do |dc|
|
115
|
+
dc.url = config[:consul]
|
116
|
+
dc.acl_token = config[:token]
|
117
|
+
headers = {}
|
118
|
+
headers['X-Consul-Token'] = config[:token] if config[:token]
|
119
|
+
dc.options = {
|
120
|
+
headers: headers
|
121
|
+
}
|
122
|
+
end
|
123
|
+
|
124
|
+
found = false
|
125
|
+
warnings = false
|
126
|
+
criticals = false
|
127
|
+
checks = []
|
128
|
+
|
129
|
+
# Process all of the nonpassing service checks
|
130
|
+
acquire_service_data.each do |d|
|
131
|
+
found = true
|
132
|
+
checkId = d['CheckID'] # rubocop:disable Style/VariableName
|
133
|
+
checkStatus = d['Status'] # rubocop:disable Style/VariableName
|
134
|
+
|
135
|
+
# If we are passing do nothing
|
136
|
+
next if checkStatus == 'passing'
|
137
|
+
|
138
|
+
checks.push(
|
139
|
+
checkId => d['Output'],
|
140
|
+
'Status' => checkStatus
|
141
|
+
)
|
142
|
+
|
143
|
+
warnings = true if %w[warning].include? checkStatus
|
144
|
+
criticals = true if %w[critical unknown].include? checkStatus
|
145
|
+
end
|
146
|
+
|
147
|
+
if config[:fail_if_not_found] && !found
|
148
|
+
msg = 'Could not find checks for any services'
|
149
|
+
if config[:service]
|
150
|
+
msg = "Could not find checks for service #{config[:service]}"
|
151
|
+
if config[:tags]
|
152
|
+
msg += " with tags #{config[:tags]}"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
critical msg
|
156
|
+
end
|
157
|
+
critical checks if criticals
|
158
|
+
warning checks if warnings
|
159
|
+
ok
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
# frozen_string_literal: false
|
3
|
+
|
4
|
+
#
|
5
|
+
# check-consul-stale-peers
|
6
|
+
#
|
7
|
+
# DESCRIPTION:
|
8
|
+
# This plugin checks the raft configuration for stale ("unknown") peers.
|
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
|
+
# Connect to localhost, go critical when there are any stale peers:
|
22
|
+
# ./check-consul-stale-peers
|
23
|
+
#
|
24
|
+
# Connect to a remote Consul server over HTTPS:
|
25
|
+
# ./check-consul-stale-peers -s 192.168.42.42 -p 4443 -P https
|
26
|
+
#
|
27
|
+
# Go critical when the cluster has two or more stale peers:
|
28
|
+
# ./check-consul-stale-peers -W 1 -C 2
|
29
|
+
#
|
30
|
+
# NOTES:
|
31
|
+
#
|
32
|
+
# LICENSE:
|
33
|
+
# Copyright 2018, Jonathan Hartman <j@hartman.io>
|
34
|
+
# Released under the same terms as Sensu (the MIT license); see LICENSE
|
35
|
+
# for details.
|
36
|
+
#
|
37
|
+
|
38
|
+
require 'sensu-plugins-consul/check/base'
|
39
|
+
|
40
|
+
#
|
41
|
+
# Consul stale peers
|
42
|
+
#
|
43
|
+
class ConsulStalePeers < SensuPluginsConsul::Check::Base
|
44
|
+
option :warning,
|
45
|
+
description: 'Warn when there are this many stale peers',
|
46
|
+
short: '-W NUMBER_OF_PEERS',
|
47
|
+
long: '--warning NUMBER_OF_PEERS',
|
48
|
+
proc: proc(&:to_i),
|
49
|
+
default: 1
|
50
|
+
|
51
|
+
option :critical,
|
52
|
+
description: 'Go critical when there are this many stale peers',
|
53
|
+
short: '-C NUMBER_OF_PEERS',
|
54
|
+
long: '--critical NUMBER_OF_PEERS',
|
55
|
+
proc: proc(&:to_i),
|
56
|
+
default: 1
|
57
|
+
|
58
|
+
def run
|
59
|
+
raft = consul_get('operator/raft/configuration')
|
60
|
+
|
61
|
+
res = raft['Servers'].select { |s| s['Node'] == '(unknown)' }.length
|
62
|
+
|
63
|
+
msg = "Cluster contains #{res} stale peer#{'s' unless res == 1}"
|
64
|
+
|
65
|
+
if res >= config[:critical]
|
66
|
+
critical msg
|
67
|
+
elsif res >= config[:warning]
|
68
|
+
warning msg
|
69
|
+
else
|
70
|
+
ok msg
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# check-service-consul
|
6
|
+
#
|
7
|
+
# DESCRIPTION:
|
8
|
+
# This plugin checks if consul says a service is 'passing' or
|
9
|
+
# 'critical'
|
10
|
+
#
|
11
|
+
# OUTPUT:
|
12
|
+
# plain text
|
13
|
+
#
|
14
|
+
# PLATFORMS:
|
15
|
+
# Linux
|
16
|
+
#
|
17
|
+
# DEPENDENCIES:
|
18
|
+
# gem: sensu-plugin
|
19
|
+
# gem: diplomat
|
20
|
+
#
|
21
|
+
# USAGE:
|
22
|
+
# ./check-service-consul -s influxdb
|
23
|
+
# ./check-service-consul -a
|
24
|
+
#
|
25
|
+
# NOTES:
|
26
|
+
#
|
27
|
+
# LICENSE:
|
28
|
+
# Copyright 2015 Yieldbot, Inc. <Sensu-Plugins>
|
29
|
+
# Released under the same terms as Sensu (the MIT license); see LICENSE
|
30
|
+
# for details.
|
31
|
+
#
|
32
|
+
|
33
|
+
require 'sensu-plugin/check/cli'
|
34
|
+
require 'diplomat'
|
35
|
+
|
36
|
+
#
|
37
|
+
# Service Status
|
38
|
+
#
|
39
|
+
class ServiceStatus < Sensu::Plugin::Check::CLI
|
40
|
+
option :consul,
|
41
|
+
description: 'consul server',
|
42
|
+
long: '--consul SERVER',
|
43
|
+
default: 'http://localhost:8500'
|
44
|
+
|
45
|
+
option :service,
|
46
|
+
description: 'a service managed by consul',
|
47
|
+
short: '-s SERVICE',
|
48
|
+
long: '--service SERVICE',
|
49
|
+
default: 'consul'
|
50
|
+
|
51
|
+
option :tags,
|
52
|
+
description: 'filter services by a comma-separated list of tags (requires --service)',
|
53
|
+
short: '-t TAGS',
|
54
|
+
long: '--tags TAGS'
|
55
|
+
|
56
|
+
option :all,
|
57
|
+
description: 'get all services in a non-passing status (not compatible with --tags)',
|
58
|
+
short: '-a',
|
59
|
+
long: '--all'
|
60
|
+
|
61
|
+
option :fail_if_not_found,
|
62
|
+
description: 'fail if no service is found',
|
63
|
+
short: '-f',
|
64
|
+
long: '--fail-if-not-found'
|
65
|
+
|
66
|
+
option :token,
|
67
|
+
description: 'ACL token',
|
68
|
+
long: '--token ACL_TOKEN'
|
69
|
+
|
70
|
+
# Get the check data for the service from consul
|
71
|
+
#
|
72
|
+
def acquire_service_data
|
73
|
+
if config[:tags] && config[:service]
|
74
|
+
tags = config[:tags].split(',').to_set
|
75
|
+
services = []
|
76
|
+
Diplomat::Health.service(config[:service]).each do |s|
|
77
|
+
if s['Service']['Tags'].to_set.superset? tags
|
78
|
+
services.push(*s['Checks'])
|
79
|
+
end
|
80
|
+
end
|
81
|
+
return services
|
82
|
+
elsif config[:all]
|
83
|
+
Diplomat::Health.state('any')
|
84
|
+
else
|
85
|
+
Diplomat::Health.checks(config[:service])
|
86
|
+
end
|
87
|
+
rescue Faraday::ConnectionFailed => e
|
88
|
+
warning "Connection error occurred: #{e}"
|
89
|
+
rescue Diplomat::UnknownStatus => e
|
90
|
+
if e.message.include?('403')
|
91
|
+
critical %(ACL token is not authorized to access service "#{config[:service]}")
|
92
|
+
else
|
93
|
+
critical "Unhandled exception(#{e.class}) -- #{e.message}"
|
94
|
+
end
|
95
|
+
rescue Faraday::ClientError => e
|
96
|
+
if e.response[:status] == 403
|
97
|
+
critical %(ACL token is not authorized to access service "#{config[:service]}": #{e.response[:body]})
|
98
|
+
else
|
99
|
+
unknown "Exception occurred when checking consul service: #{e}"
|
100
|
+
end
|
101
|
+
rescue StandardError => e
|
102
|
+
unknown "Exception occurred when checking consul service: #{e}"
|
103
|
+
end
|
104
|
+
|
105
|
+
# Main function
|
106
|
+
#
|
107
|
+
def run
|
108
|
+
if config[:tags] && config[:all]
|
109
|
+
critical 'Cannot specify --tags and --all simultaneously (Consul health/service/ versus health/state/).'
|
110
|
+
end
|
111
|
+
|
112
|
+
Diplomat.configure do |dc|
|
113
|
+
dc.url = config[:consul]
|
114
|
+
dc.acl_token = config[:token]
|
115
|
+
dc.options = {
|
116
|
+
headers: {
|
117
|
+
'X-Consul-Token' => config[:token]
|
118
|
+
}
|
119
|
+
}
|
120
|
+
end
|
121
|
+
|
122
|
+
data = acquire_service_data
|
123
|
+
passing = []
|
124
|
+
failing = []
|
125
|
+
data.each do |d|
|
126
|
+
if d['Status'] == 'passing'
|
127
|
+
passing << {
|
128
|
+
'node' => d['Node'],
|
129
|
+
'service' => d['ServiceName'],
|
130
|
+
'service_id' => d['ServiceID'],
|
131
|
+
'notes' => d['Notes']
|
132
|
+
}
|
133
|
+
elsif d['Status'] == 'critical'
|
134
|
+
failing << {
|
135
|
+
'node' => d['Node'],
|
136
|
+
'service' => d['ServiceName'],
|
137
|
+
'service_id' => d['ServiceID'],
|
138
|
+
'notes' => d['Notes']
|
139
|
+
}
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
if failing.empty? && passing.empty?
|
144
|
+
msg = 'Could not find checks for any services'
|
145
|
+
if config[:service]
|
146
|
+
msg = "Could not find checks for service #{config[:service]}"
|
147
|
+
if config[:tags]
|
148
|
+
msg += " with tags #{config[:tags]}"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
if config[:fail_if_not_found]
|
152
|
+
critical msg
|
153
|
+
else
|
154
|
+
unknown msg
|
155
|
+
end
|
156
|
+
end
|
157
|
+
critical failing unless failing.empty?
|
158
|
+
ok passing unless passing.empty?
|
159
|
+
end
|
160
|
+
end
|