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