sensu-plugins-consul-magec 2.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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,129 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# check-consul-leader
|
6
|
+
#
|
7
|
+
# DESCRIPTION:
|
8
|
+
# This plugin checks if consul is up and reachable. It then checks
|
9
|
+
# the status/leader and ensures there is a current leader.
|
10
|
+
#
|
11
|
+
# OUTPUT:
|
12
|
+
# plain text
|
13
|
+
#
|
14
|
+
# PLATFORMS:
|
15
|
+
# Linux
|
16
|
+
#
|
17
|
+
# DEPENDENCIES:
|
18
|
+
# gem: sensu-plugin
|
19
|
+
# gem: rest-client
|
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 'resolv'
|
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 :scheme,
|
53
|
+
description: 'consul listener scheme',
|
54
|
+
short: '-S SCHEME',
|
55
|
+
long: '--scheme SCHEME',
|
56
|
+
default: 'http'
|
57
|
+
|
58
|
+
option :insecure,
|
59
|
+
description: 'set this flag to disable SSL verification',
|
60
|
+
short: '-k',
|
61
|
+
long: '--insecure',
|
62
|
+
boolean: true,
|
63
|
+
default: false
|
64
|
+
|
65
|
+
option :capath,
|
66
|
+
description: 'absolute path to an alternative CA file',
|
67
|
+
short: '-c CAPATH',
|
68
|
+
long: '--capath CAPATH'
|
69
|
+
|
70
|
+
option :timeout,
|
71
|
+
description: 'connection will time out after this many seconds',
|
72
|
+
short: '-t TIMEOUT_IN_SECONDS',
|
73
|
+
long: '--timeout TIMEOUT_IN_SECONDS',
|
74
|
+
proc: proc { |t| t.to_i },
|
75
|
+
default: 5
|
76
|
+
|
77
|
+
option :token,
|
78
|
+
description: 'ACL token',
|
79
|
+
long: '--token ACL_TOKEN'
|
80
|
+
|
81
|
+
def valid_ip(ip)
|
82
|
+
case ip.to_s
|
83
|
+
when Resolv::IPv4::Regex
|
84
|
+
true
|
85
|
+
when Resolv::IPv6::Regex
|
86
|
+
true
|
87
|
+
else
|
88
|
+
false
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def strip_ip(str)
|
93
|
+
ipv4_regex = '(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])'
|
94
|
+
ipv6_regex = '\[.*\]'
|
95
|
+
if str =~ /^.*#{ipv4_regex}.*$/ # rubocop:disable Style/GuardClause
|
96
|
+
return str.match(/#{ipv4_regex}/)
|
97
|
+
elsif str =~ /^.*#{ipv6_regex}.*$/
|
98
|
+
return str[/#{ipv6_regex}/][1..-2]
|
99
|
+
else
|
100
|
+
return str
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def run
|
105
|
+
options = { timeout: config[:timeout],
|
106
|
+
verify_ssl: (OpenSSL::SSL::VERIFY_NONE if defined? config[:insecure]),
|
107
|
+
ssl_ca_file: (config[:capath] if defined? config[:capath]),
|
108
|
+
headers: { 'X-Consul-Token' => config[:token] } }
|
109
|
+
url = "#{config[:scheme]}://#{config[:server]}:#{config[:port]}/v1/status/leader"
|
110
|
+
|
111
|
+
r = RestClient::Resource.new(url, options).get
|
112
|
+
|
113
|
+
if r.code == 200
|
114
|
+
if valid_ip(strip_ip(r.body))
|
115
|
+
ok 'Consul is UP and has a leader'
|
116
|
+
else
|
117
|
+
critical 'Consul is UP, but it has NO leader'
|
118
|
+
end
|
119
|
+
else
|
120
|
+
critical 'Consul is not responding'
|
121
|
+
end
|
122
|
+
rescue Errno::ECONNREFUSED
|
123
|
+
critical 'Consul is not responding'
|
124
|
+
rescue RestClient::RequestTimeout
|
125
|
+
critical 'Consul Connection timed out'
|
126
|
+
rescue RestClient::Exception => e
|
127
|
+
unknown "Consul returned: #{e}"
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# check-consul-maintenance
|
6
|
+
#
|
7
|
+
# DESCRIPTION:
|
8
|
+
# This plugin checks if maintenance mode is enabled
|
9
|
+
# for the node in Consul
|
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-consul-maintenance -n localhost
|
23
|
+
#
|
24
|
+
# NOTES:
|
25
|
+
#
|
26
|
+
# LICENSE:
|
27
|
+
# Copyright 2016 Oleksandr Kushchenko <gearok@gmail.com>
|
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 'diplomat'
|
34
|
+
|
35
|
+
#
|
36
|
+
# Maintenance Status
|
37
|
+
#
|
38
|
+
class MaintenanceStatus < Sensu::Plugin::Check::CLI
|
39
|
+
option :consul,
|
40
|
+
description: 'consul server',
|
41
|
+
long: '--consul SERVER',
|
42
|
+
default: 'http://localhost:8500'
|
43
|
+
|
44
|
+
option :node,
|
45
|
+
description: 'consul node name',
|
46
|
+
short: '-n NODE',
|
47
|
+
long: '--node NODE',
|
48
|
+
default: 'localhost'
|
49
|
+
|
50
|
+
option :token,
|
51
|
+
description: 'ACL token',
|
52
|
+
long: '--token ACL_TOKEN'
|
53
|
+
|
54
|
+
# Get the maintenance data for the node from consul
|
55
|
+
#
|
56
|
+
def acquire_maintenance_data
|
57
|
+
result = Diplomat::Health.node(config[:node]).select do |check|
|
58
|
+
check['CheckID'] == '_node_maintenance'
|
59
|
+
end
|
60
|
+
if !result.empty?
|
61
|
+
{ enabled: true, reason: result.first['Notes'] }
|
62
|
+
else
|
63
|
+
{ enabled: false, reason: nil }
|
64
|
+
end
|
65
|
+
rescue Faraday::ConnectionFailed => e
|
66
|
+
warning "Connection error occurred: #{e}"
|
67
|
+
rescue Faraday::ClientError => e
|
68
|
+
if e.response[:status] == 403
|
69
|
+
critical %(ACL token is not authorized to access resource: #{e.response[:body]})
|
70
|
+
else
|
71
|
+
unknown "Exception occurred when checking consul service: #{e}"
|
72
|
+
end
|
73
|
+
rescue StandardError => e
|
74
|
+
unknown "Exception occurred when checking consul node maintenance: #{e}"
|
75
|
+
end
|
76
|
+
|
77
|
+
# Main function
|
78
|
+
#
|
79
|
+
def run
|
80
|
+
Diplomat.configure do |dc|
|
81
|
+
dc.url = config[:consul]
|
82
|
+
dc.acl_token = config[:token]
|
83
|
+
dc.options = {
|
84
|
+
headers: {
|
85
|
+
'X-Consul-Token' => config[:token]
|
86
|
+
}
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
data = acquire_maintenance_data
|
91
|
+
|
92
|
+
if data[:enabled]
|
93
|
+
critical "Maintenance enabled for node #{config[:node]}: #{data[:reason]}"
|
94
|
+
else
|
95
|
+
ok "Maintenance disabled for node #{config[:node]}"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# check-consul-members
|
6
|
+
#
|
7
|
+
# DESCRIPTION:
|
8
|
+
# This plugin checks if consul is up and reachable. It then checks
|
9
|
+
# the status of the members of the cluster to determine if the correct
|
10
|
+
# number of peers are reporting as 'alive'
|
11
|
+
#
|
12
|
+
# OUTPUT:
|
13
|
+
# plain text
|
14
|
+
#
|
15
|
+
# PLATFORMS:
|
16
|
+
# Linux
|
17
|
+
#
|
18
|
+
# DEPENDENCIES:
|
19
|
+
# gem: sensu-plugin
|
20
|
+
# gem: rest-client
|
21
|
+
# gem: json
|
22
|
+
#
|
23
|
+
# USAGE:
|
24
|
+
# Check to make sure the min number of peers needed is present in the cluster
|
25
|
+
# ./check-consul-members -s 127.0.0.1 -p 8500 -g 5 -e 8
|
26
|
+
#
|
27
|
+
# NOTES:
|
28
|
+
#
|
29
|
+
# LICENSE:
|
30
|
+
# Copyright 2015 Sonian, Inc. and contributors. <support@sensuapp.org>
|
31
|
+
# Released under the same terms as Sensu (the MIT license); see LICENSE
|
32
|
+
# for details.
|
33
|
+
#
|
34
|
+
|
35
|
+
require 'sensu-plugin/check/cli'
|
36
|
+
require 'rest-client'
|
37
|
+
require 'json'
|
38
|
+
|
39
|
+
#
|
40
|
+
# Consul Status
|
41
|
+
#
|
42
|
+
class ConsulStatus < Sensu::Plugin::Check::CLI
|
43
|
+
option :server,
|
44
|
+
description: 'consul server',
|
45
|
+
short: '-s SERVER',
|
46
|
+
long: '--server SERVER',
|
47
|
+
default: '127.0.0.1'
|
48
|
+
|
49
|
+
option :port,
|
50
|
+
description: 'consul http port',
|
51
|
+
short: '-p PORT',
|
52
|
+
long: '--port PORT',
|
53
|
+
default: '8500'
|
54
|
+
|
55
|
+
option :min,
|
56
|
+
description: 'minimum number of peers',
|
57
|
+
short: '-g GREATER THAN',
|
58
|
+
long: '--greater GREATER THAN',
|
59
|
+
default: 3
|
60
|
+
|
61
|
+
option :expected,
|
62
|
+
description: 'expected number of peers',
|
63
|
+
short: '-e EXPECT',
|
64
|
+
long: '--expect EXPECT',
|
65
|
+
default: 5
|
66
|
+
|
67
|
+
option :wan,
|
68
|
+
description: 'whether to check the wan members',
|
69
|
+
short: '-w',
|
70
|
+
long: '--wan',
|
71
|
+
boolean: false
|
72
|
+
|
73
|
+
option :scheme,
|
74
|
+
description: 'consul listener scheme',
|
75
|
+
short: '-S SCHEME',
|
76
|
+
long: '--scheme SCHEME',
|
77
|
+
default: 'http'
|
78
|
+
|
79
|
+
option :insecure,
|
80
|
+
description: 'if set, disables SSL verification',
|
81
|
+
short: '-k',
|
82
|
+
long: '--insecure',
|
83
|
+
boolean: true,
|
84
|
+
default: false
|
85
|
+
|
86
|
+
option :capath,
|
87
|
+
description: 'absolute path to an alternate CA file',
|
88
|
+
short: '-c CAPATH',
|
89
|
+
long: '--capath CAPATH'
|
90
|
+
|
91
|
+
option :timeout,
|
92
|
+
description: 'connection will time out after this many seconds',
|
93
|
+
short: '-t TIMEOUT_IN_SECONDS',
|
94
|
+
long: '--timeout TIMEOUT_IN_SECONDS',
|
95
|
+
default: 5
|
96
|
+
|
97
|
+
option :token,
|
98
|
+
description: 'ACL token',
|
99
|
+
long: '--token ACL_TOKEN'
|
100
|
+
|
101
|
+
def run
|
102
|
+
url = "#{config[:scheme]}://#{config[:server]}:#{config[:port]}/v1/agent/members"
|
103
|
+
options = { timeout: config[:timeout],
|
104
|
+
verify_ssl: (OpenSSL::SSL::VERIFY_NONE if defined? config[:insecure]),
|
105
|
+
ssl_ca_file: (config[:capath] if defined? config[:capath]),
|
106
|
+
headers: { 'X-Consul-Token' => config[:token] } }
|
107
|
+
|
108
|
+
if config[:wan]
|
109
|
+
url += '?wan=1'
|
110
|
+
end
|
111
|
+
|
112
|
+
json = RestClient::Resource.new(url, options).get
|
113
|
+
peers = 0
|
114
|
+
members = JSON.parse(json)
|
115
|
+
members.each do |member|
|
116
|
+
# only count the member if its status is alive
|
117
|
+
if member.key?('Tags') && member['Tags']['role'] == 'consul' && member['Status'] == 1
|
118
|
+
peers += 1
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
if peers < config[:min].to_i
|
123
|
+
critical "[#{peers}] peers is below critical threshold of [#{config[:min]}]"
|
124
|
+
elsif peers != config[:expected].to_i
|
125
|
+
warning "[#{peers}] peers is outside of expected count of [#{config[:expected]}]"
|
126
|
+
else
|
127
|
+
ok 'Peers within threshold'
|
128
|
+
end
|
129
|
+
rescue Errno::ECONNREFUSED
|
130
|
+
critical 'Consul is not responding'
|
131
|
+
rescue RestClient::RequestTimeout
|
132
|
+
critical 'Consul Connection timed out'
|
133
|
+
rescue RestClient::Exception => e
|
134
|
+
unknown "Consul returned: #{e}"
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
# frozen_string_literal: false
|
3
|
+
|
4
|
+
#
|
5
|
+
# check-consul-quorum
|
6
|
+
#
|
7
|
+
# DESCRIPTION:
|
8
|
+
# This plugin checks how many nodes the cluster will be able to lose while
|
9
|
+
# still maintaining quorum.
|
10
|
+
#
|
11
|
+
# OUTPUT:
|
12
|
+
# plain text
|
13
|
+
#
|
14
|
+
# PLATFORMS:
|
15
|
+
# Linux
|
16
|
+
#
|
17
|
+
# DEPENDENCIES:
|
18
|
+
# gem: sensu-plugin
|
19
|
+
# gem: rest-client
|
20
|
+
#
|
21
|
+
# USAGE:
|
22
|
+
# Connect to localhost, go critical when the cluster is at its minimum for
|
23
|
+
# quorum:
|
24
|
+
# ./check-consul-quorum
|
25
|
+
#
|
26
|
+
# Connect to a remote Consul server over HTTPS:
|
27
|
+
# ./check-consul-quorum -s 192.168.42.42 -p 4443 -P https
|
28
|
+
#
|
29
|
+
# Go critical when the cluster can lose one more server and keep quorum:
|
30
|
+
# ./check-consul-quorum -W 2 -C 1
|
31
|
+
#
|
32
|
+
# NOTES:
|
33
|
+
#
|
34
|
+
# LICENSE:
|
35
|
+
# Copyright 2018, Jonathan Hartman <j@hartman.io>
|
36
|
+
# Released under the same terms as Sensu (the MIT license); see LICENSE
|
37
|
+
# for details.
|
38
|
+
#
|
39
|
+
|
40
|
+
require 'sensu-plugins-consul/check/base'
|
41
|
+
|
42
|
+
#
|
43
|
+
# Consul quorum status
|
44
|
+
#
|
45
|
+
class ConsulQuorumStatus < SensuPluginsConsul::Check::Base
|
46
|
+
option :warning,
|
47
|
+
description: 'Warn when the cluster has this many spare servers ' \
|
48
|
+
'beyond the minimum for quorum',
|
49
|
+
short: '-W NUMBER_OF_SPARE_SERVERS',
|
50
|
+
long: '--warning NUMBER_OF_SPARE_SERVERS',
|
51
|
+
proc: proc(&:to_i),
|
52
|
+
default: 1
|
53
|
+
|
54
|
+
option :critical,
|
55
|
+
description: 'Go critical when the cluster has this many spare ' \
|
56
|
+
'servers beyond the minimum for quorum',
|
57
|
+
short: '-C NUMBER_OF_SPARE_SERVERS',
|
58
|
+
long: '--critical NUMBER_OF_SPARE_SERVERS',
|
59
|
+
proc: proc(&:to_i),
|
60
|
+
default: 0
|
61
|
+
|
62
|
+
def run
|
63
|
+
raft = consul_get('operator/raft/configuration')
|
64
|
+
members = consul_get('agent/members')
|
65
|
+
|
66
|
+
total = raft['Servers'].select { |s| s['Voter'] == true }.length
|
67
|
+
required = total / 2 + 1
|
68
|
+
alive = members.select do |m|
|
69
|
+
m.key?('Tags') && m['Tags']['role'] == 'consul' && m['Status'] == 1
|
70
|
+
end.length
|
71
|
+
|
72
|
+
spares = alive - required
|
73
|
+
|
74
|
+
msg = "Cluster has #{alive}/#{total} servers alive and"
|
75
|
+
msg = if spares < 0
|
76
|
+
"#{msg} has lost quorum"
|
77
|
+
elsif spares.zero?
|
78
|
+
"#{msg} has the minimum required for quorum"
|
79
|
+
else
|
80
|
+
"#{msg} can lose #{spares} more without losing quorum"
|
81
|
+
end
|
82
|
+
|
83
|
+
if spares < 0 || spares <= config[:critical]
|
84
|
+
critical msg
|
85
|
+
elsif spares <= config[:warning]
|
86
|
+
warning msg
|
87
|
+
else
|
88
|
+
ok msg
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|