sensu-plugins-mysql-boutetnico 1.0.0
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 +1 -0
- data/LICENSE +22 -0
- data/README.md +161 -0
- data/bin/check-mysql-alive.rb +102 -0
- data/bin/check-mysql-connections.rb +110 -0
- data/bin/check-mysql-disk.rb +137 -0
- data/bin/check-mysql-innodb-lock.rb +148 -0
- data/bin/check-mysql-msr-replication-status.rb +157 -0
- data/bin/check-mysql-query-result-count.rb +110 -0
- data/bin/check-mysql-replication-status.rb +185 -0
- data/bin/check-mysql-select-count.rb +113 -0
- data/bin/check-mysql-status.rb +209 -0
- data/bin/check-mysql-threads.rb +122 -0
- data/bin/metrics-mysql-graphite.rb +273 -0
- data/bin/metrics-mysql-multiple-select-count.rb +110 -0
- data/bin/metrics-mysql-processes.rb +149 -0
- data/bin/metrics-mysql-query-result-count.rb +97 -0
- data/bin/metrics-mysql-raw.rb +397 -0
- data/bin/metrics-mysql-select-count.rb +99 -0
- data/bin/metrics-mysql.rb +58 -0
- data/bin/mysql-metrics.sql +15 -0
- data/lib/sensu-plugins-mysql.rb +1 -0
- data/lib/sensu-plugins-mysql/version.rb +9 -0
- metadata +262 -0
@@ -0,0 +1,148 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# MySQL InnoDB Lock Check Plugin
|
4
|
+
# ===
|
5
|
+
#
|
6
|
+
# This plugin checks InnoDB locks.
|
7
|
+
#
|
8
|
+
# Copyright 2014 Hiroaki Sano <hiroaki.sano.9stories@gmail.com>
|
9
|
+
#
|
10
|
+
# Released under the same terms as Sensu (the MIT license); see LICENSE
|
11
|
+
# for details.
|
12
|
+
|
13
|
+
require 'sensu-plugin/check/cli'
|
14
|
+
require 'mysql'
|
15
|
+
require 'inifile'
|
16
|
+
|
17
|
+
class CheckMySQLInnoDBLock < Sensu::Plugin::Check::CLI
|
18
|
+
option :user,
|
19
|
+
description: 'MySQL User',
|
20
|
+
short: '-u USER',
|
21
|
+
long: '--user USER',
|
22
|
+
default: 'root'
|
23
|
+
|
24
|
+
option :password,
|
25
|
+
description: 'MySQL Password',
|
26
|
+
short: '-p PASS',
|
27
|
+
long: '--password PASS'
|
28
|
+
|
29
|
+
option :ini,
|
30
|
+
description: 'My.cnf ini file',
|
31
|
+
short: '-i',
|
32
|
+
long: '--ini VALUE'
|
33
|
+
|
34
|
+
option :ini_section,
|
35
|
+
description: 'Section in my.cnf ini file',
|
36
|
+
long: '--ini-section VALUE',
|
37
|
+
default: 'client'
|
38
|
+
|
39
|
+
option :hostname,
|
40
|
+
description: 'Hostname to login to',
|
41
|
+
short: '-h HOST',
|
42
|
+
long: '--hostname HOST',
|
43
|
+
default: 'localhost'
|
44
|
+
|
45
|
+
option :port,
|
46
|
+
description: 'Port to connect to',
|
47
|
+
short: '-P PORT',
|
48
|
+
long: '--port PORT',
|
49
|
+
default: '3306'
|
50
|
+
|
51
|
+
option :socket,
|
52
|
+
description: 'Socket to use',
|
53
|
+
short: '-s SOCKET',
|
54
|
+
long: '--socket SOCKET'
|
55
|
+
|
56
|
+
option :warn,
|
57
|
+
description: 'Warning threshold',
|
58
|
+
short: '-w SECONDS',
|
59
|
+
long: '--warning SECONDS',
|
60
|
+
default: 5
|
61
|
+
|
62
|
+
option :crit,
|
63
|
+
description: 'Critical threshold',
|
64
|
+
short: '-c SECONDS',
|
65
|
+
long: '--critical SECONDS',
|
66
|
+
default: 10
|
67
|
+
|
68
|
+
def run
|
69
|
+
if config[:ini]
|
70
|
+
ini = IniFile.load(config[:ini])
|
71
|
+
section = ini[config[:ini_section]]
|
72
|
+
db_user = section['user']
|
73
|
+
db_pass = section['password']
|
74
|
+
else
|
75
|
+
db_user = config[:user]
|
76
|
+
db_pass = config[:password]
|
77
|
+
end
|
78
|
+
db = Mysql.new(config[:hostname], db_user, db_pass, config[:database], config[:port].to_i, config[:socket])
|
79
|
+
|
80
|
+
warn = config[:warn].to_i
|
81
|
+
crit = config[:crit].to_i
|
82
|
+
|
83
|
+
res = db.query <<-EQSQL
|
84
|
+
select
|
85
|
+
t_b.trx_mysql_thread_id blocking_id,
|
86
|
+
t_w.trx_mysql_thread_id requesting_id,
|
87
|
+
p_b.HOST blocking_host,
|
88
|
+
p_w.HOST requesting_host,
|
89
|
+
l.lock_table lock_table,
|
90
|
+
l.lock_index lock_index,
|
91
|
+
l.lock_mode lock_mode,
|
92
|
+
p_w.TIME seconds,
|
93
|
+
p_b.INFO blocking_info,
|
94
|
+
p_w.INFO requesting_info
|
95
|
+
from
|
96
|
+
information_schema.INNODB_LOCK_WAITS w,
|
97
|
+
information_schema.INNODB_LOCKS l,
|
98
|
+
information_schema.INNODB_TRX t_b,
|
99
|
+
information_schema.INNODB_TRX t_w,
|
100
|
+
information_schema.PROCESSLIST p_b,
|
101
|
+
information_schema.PROCESSLIST p_w
|
102
|
+
where
|
103
|
+
w.blocking_lock_id = l.lock_id
|
104
|
+
and
|
105
|
+
w.blocking_trx_id = t_b.trx_id
|
106
|
+
and
|
107
|
+
w.requesting_trx_id = t_w.trx_id
|
108
|
+
and
|
109
|
+
t_b.trx_mysql_thread_id = p_b.ID
|
110
|
+
and
|
111
|
+
t_w.trx_mysql_thread_id = p_w.ID
|
112
|
+
and
|
113
|
+
p_w.TIME > #{warn}
|
114
|
+
order by
|
115
|
+
requesting_id,blocking_id
|
116
|
+
EQSQL
|
117
|
+
|
118
|
+
lock_info = []
|
119
|
+
is_crit = false
|
120
|
+
res.each_hash do |row|
|
121
|
+
h = {}
|
122
|
+
is_crit = true if row['seconds'].to_i > crit
|
123
|
+
h['blocking_id'] = row['blocking_id']
|
124
|
+
h['requesting_id'] = row['requesting_id']
|
125
|
+
h['blocking_host'] = row['blocking_host']
|
126
|
+
h['requesting_host'] = row['requesting_host']
|
127
|
+
h['lock_table'] = row['lock_table']
|
128
|
+
h['lock_index'] = row['lock_index']
|
129
|
+
h['lock_mode'] = row['lock_mode']
|
130
|
+
h['seconds'] = row['seconds']
|
131
|
+
h['blocking_info'] = row['blocking_info']
|
132
|
+
h['requesting_info'] = row['requesting_info']
|
133
|
+
lock_info.push(h)
|
134
|
+
end
|
135
|
+
|
136
|
+
if lock_info.length == 0 # rubocop:disable Style/ZeroLengthPredicate
|
137
|
+
ok
|
138
|
+
elsif is_crit == false
|
139
|
+
warning "Detected Locks #{lock_info}"
|
140
|
+
else
|
141
|
+
critical "Detected Locks #{lock_info}"
|
142
|
+
end
|
143
|
+
rescue Mysql::Error => e
|
144
|
+
critical "MySQL check failed: #{e.error}"
|
145
|
+
ensure
|
146
|
+
db.close if db
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# MySQL Multi-source Replication Status
|
4
|
+
# ===
|
5
|
+
#
|
6
|
+
#
|
7
|
+
# EXAMPLE
|
8
|
+
# check-mysql-msr-replication-status.rb -h db01 --ini '/etc/sensu/my.cnf'
|
9
|
+
# check-mysql-msr-replication-status.rb -h db01 --ini '/etc/sensu/my.cnf' --ini-section customsection
|
10
|
+
#
|
11
|
+
# MY.CNF INI FORMAT
|
12
|
+
# [client]
|
13
|
+
# user=sensu
|
14
|
+
# password="abcd1234"
|
15
|
+
#
|
16
|
+
# [customsection]
|
17
|
+
# user=user
|
18
|
+
# password="password"
|
19
|
+
#
|
20
|
+
|
21
|
+
require 'sensu-plugin/check/cli'
|
22
|
+
require 'mysql'
|
23
|
+
require 'inifile'
|
24
|
+
|
25
|
+
class CheckMysqlMSRReplicationStatus < Sensu::Plugin::Check::CLI
|
26
|
+
option :host,
|
27
|
+
short: '-h',
|
28
|
+
long: '--host VALUE',
|
29
|
+
description: 'Database host'
|
30
|
+
|
31
|
+
option :port,
|
32
|
+
short: '-P',
|
33
|
+
long: '--port VALUE',
|
34
|
+
description: 'Database port',
|
35
|
+
default: 3306,
|
36
|
+
proc: proc(&:to_i)
|
37
|
+
|
38
|
+
option :socket,
|
39
|
+
short: '-s SOCKET',
|
40
|
+
long: '--socket SOCKET',
|
41
|
+
description: 'Socket to use'
|
42
|
+
|
43
|
+
option :user,
|
44
|
+
short: '-u',
|
45
|
+
long: '--username VALUE',
|
46
|
+
description: 'Database username'
|
47
|
+
|
48
|
+
option :pass,
|
49
|
+
short: '-p',
|
50
|
+
long: '--password VALUE',
|
51
|
+
description: 'Database password'
|
52
|
+
|
53
|
+
option :ini,
|
54
|
+
short: '-i',
|
55
|
+
long: '--ini VALUE',
|
56
|
+
description: 'My.cnf ini file'
|
57
|
+
|
58
|
+
option :ini_section,
|
59
|
+
description: 'Section in my.cnf ini file',
|
60
|
+
long: '--ini-section VALUE',
|
61
|
+
default: 'client'
|
62
|
+
|
63
|
+
option :warn,
|
64
|
+
short: '-w',
|
65
|
+
long: '--warning VALUE',
|
66
|
+
description: 'Warning threshold for replication lag',
|
67
|
+
default: 900,
|
68
|
+
proc: proc(&:to_i)
|
69
|
+
|
70
|
+
option :crit,
|
71
|
+
short: '-c',
|
72
|
+
long: '--critical=VALUE',
|
73
|
+
description: 'Critical threshold for replication lag',
|
74
|
+
default: 1800,
|
75
|
+
proc: proc(&:to_i)
|
76
|
+
|
77
|
+
def set_status(io_thread_status, sql_thread_status, seconds_behind_master)
|
78
|
+
if io_thread_status == 'No' || sql_thread_status == 'No' || seconds_behind_master > config[:crit]
|
79
|
+
2
|
80
|
+
elsif seconds_behind_master > config[:warn] && seconds_behind_master <= config[:crit]
|
81
|
+
1
|
82
|
+
else
|
83
|
+
0
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def run
|
88
|
+
if config[:ini]
|
89
|
+
ini = IniFile.load(config[:ini])
|
90
|
+
section = ini[config[:ini_section]]
|
91
|
+
db_user = section['user']
|
92
|
+
db_pass = section['password']
|
93
|
+
else
|
94
|
+
db_user = config[:user]
|
95
|
+
db_pass = config[:pass]
|
96
|
+
end
|
97
|
+
db_host = config[:host]
|
98
|
+
|
99
|
+
if [db_host, db_user, db_pass].any?(&:nil?)
|
100
|
+
unknown 'Must specify host, user, password'
|
101
|
+
end
|
102
|
+
|
103
|
+
begin
|
104
|
+
ok_statuses = []
|
105
|
+
warn_statuses = []
|
106
|
+
crit_statuses = []
|
107
|
+
output = []
|
108
|
+
|
109
|
+
db = Mysql.new(db_host, db_user, db_pass, nil, config[:port], config[:socket])
|
110
|
+
channels = db.query('SELECT channel_name FROM performance_schema.replication_connection_status')
|
111
|
+
|
112
|
+
channels.num_rows.times do
|
113
|
+
channel = channels.fetch_hash
|
114
|
+
results = db.query("SHOW SLAVE STATUS FOR CHANNEL \'#{channel['channel_name']}\'")
|
115
|
+
results.each_hash do |row|
|
116
|
+
io_thread_status = row['Slave_IO_Running']
|
117
|
+
sql_thread_status = row['Slave_SQL_Running']
|
118
|
+
seconds_behind_master = row['Seconds_Behind_Master'].to_i
|
119
|
+
status = set_status
|
120
|
+
message = "#{channel['channel_name']} STATES:"
|
121
|
+
message += " Slave_IO_Running=#{io_thread_status}"
|
122
|
+
message += ", Slave_SQL_Running=#{sql_thread_status}"
|
123
|
+
message += ", Seconds_Behind_Master=#{seconds_behind_master}"
|
124
|
+
|
125
|
+
if status == 0
|
126
|
+
ok_statuses << message
|
127
|
+
elsif status == 1
|
128
|
+
warn_statuses << message
|
129
|
+
elsif status == 2
|
130
|
+
crit_statuses << message
|
131
|
+
else
|
132
|
+
puts 'Undefined status.'
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
output << crit_statuses unless crit_statuses.empty?
|
137
|
+
output << warn_statuses unless warn_statuses.empty?
|
138
|
+
output << ok_statuses unless ok_statuses.empty?
|
139
|
+
|
140
|
+
if !crit_statuses.empty?
|
141
|
+
critical output
|
142
|
+
elsif !warn_statuses.empty?
|
143
|
+
warning output
|
144
|
+
else
|
145
|
+
ok output
|
146
|
+
end
|
147
|
+
rescue Mysql::Error => e
|
148
|
+
errstr = "Error code: #{e.errno} Error message: #{e.error}"
|
149
|
+
errstr += "SQLSTATE: #{e.sqlstate}" if e.respond_to?('sqlstate')
|
150
|
+
critical errstr
|
151
|
+
rescue StandardError => e
|
152
|
+
critical "unhandled exception: #{e}"
|
153
|
+
ensure
|
154
|
+
db.close if db
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# MySQL Query Result Count Check
|
4
|
+
#
|
5
|
+
# Checks the length of a result set from a MySQL query.
|
6
|
+
#
|
7
|
+
# Copyright 2017 Andrew Thal <athal7@me.com>
|
8
|
+
#
|
9
|
+
# Released under the same terms as Sensu (the MIT license); see LICENSE
|
10
|
+
# for details.
|
11
|
+
|
12
|
+
require 'sensu-plugin/check/cli'
|
13
|
+
require 'mysql'
|
14
|
+
require 'inifile'
|
15
|
+
|
16
|
+
class MysqlQueryCountCheck < Sensu::Plugin::Check::CLI
|
17
|
+
option :host,
|
18
|
+
short: '-h HOST',
|
19
|
+
long: '--host HOST',
|
20
|
+
description: 'MySQL Host to connect to',
|
21
|
+
required: true
|
22
|
+
|
23
|
+
option :port,
|
24
|
+
short: '-P PORT',
|
25
|
+
long: '--port PORT',
|
26
|
+
description: 'MySQL Port to connect to',
|
27
|
+
proc: proc(&:to_i),
|
28
|
+
default: 3306
|
29
|
+
|
30
|
+
option :username,
|
31
|
+
short: '-u USERNAME',
|
32
|
+
long: '--user USERNAME',
|
33
|
+
description: 'MySQL Username'
|
34
|
+
|
35
|
+
option :password,
|
36
|
+
short: '-p PASSWORD',
|
37
|
+
long: '--pass PASSWORD',
|
38
|
+
description: 'MySQL password',
|
39
|
+
default: ''
|
40
|
+
|
41
|
+
option :database,
|
42
|
+
short: '-d DATABASE',
|
43
|
+
long: '--database DATABASE',
|
44
|
+
description: 'MySQL database',
|
45
|
+
required: true
|
46
|
+
|
47
|
+
option :ini,
|
48
|
+
short: '-i',
|
49
|
+
long: '--ini VALUE',
|
50
|
+
description: 'My.cnf ini file'
|
51
|
+
|
52
|
+
option :ini_section,
|
53
|
+
description: 'Section in my.cnf ini file',
|
54
|
+
long: '--ini-section VALUE',
|
55
|
+
default: 'client'
|
56
|
+
|
57
|
+
option :socket,
|
58
|
+
short: '-S SOCKET',
|
59
|
+
long: '--socket SOCKET',
|
60
|
+
description: 'MySQL Unix socket to connect to'
|
61
|
+
|
62
|
+
option :warn,
|
63
|
+
short: '-w COUNT',
|
64
|
+
long: '--warning COUNT',
|
65
|
+
description: 'COUNT warning threshold for number of items returned by the query',
|
66
|
+
proc: proc(&:to_i),
|
67
|
+
required: true
|
68
|
+
|
69
|
+
option :crit,
|
70
|
+
short: '-c COUNT',
|
71
|
+
long: '--critical COUNT',
|
72
|
+
description: 'COUNT critical threshold for number of items returned by the query',
|
73
|
+
proc: proc(&:to_i),
|
74
|
+
required: true
|
75
|
+
|
76
|
+
option :query,
|
77
|
+
short: '-q QUERY',
|
78
|
+
long: '--query QUERY',
|
79
|
+
description: 'Query to execute',
|
80
|
+
required: true
|
81
|
+
|
82
|
+
def run
|
83
|
+
if config[:ini]
|
84
|
+
ini = IniFile.load(config[:ini])
|
85
|
+
section = ini[config[:ini_section]]
|
86
|
+
db_user = section['user']
|
87
|
+
db_pass = section['password']
|
88
|
+
else
|
89
|
+
db_user = config[:username]
|
90
|
+
db_pass = config[:password]
|
91
|
+
end
|
92
|
+
db = Mysql.real_connect(config[:host], db_user, db_pass, config[:database], config[:port].to_i, config[:socket])
|
93
|
+
length = db.query(config[:query]).count
|
94
|
+
|
95
|
+
if length >= config[:crit]
|
96
|
+
critical "Result count is above the CRITICAL limit: #{length} length / #{config[:crit]} limit"
|
97
|
+
elsif length >= config[:warn]
|
98
|
+
warning "Result count is above the WARNING limit: #{length} length / #{config[:warn]} limit"
|
99
|
+
else
|
100
|
+
ok 'Result count length is below thresholds'
|
101
|
+
end
|
102
|
+
rescue Mysql::Error => e
|
103
|
+
errstr = "Error code: #{e.errno} Error message: #{e.error}"
|
104
|
+
critical "#{errstr} SQLSTATE: #{e.sqlstate}" if e.respond_to?('sqlstate')
|
105
|
+
rescue StandardError => e
|
106
|
+
critical e
|
107
|
+
ensure
|
108
|
+
db.close if db
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,185 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# MySQL Replication Status (modded from disk)
|
4
|
+
# ===
|
5
|
+
#
|
6
|
+
# Copyright 2011 Sonian, Inc <chefs@sonian.net>
|
7
|
+
# Updated by Oluwaseun Obajobi 2014 to accept ini argument
|
8
|
+
# Updated by Nicola Strappazzon 2016 to implement Multi Source Replication
|
9
|
+
#
|
10
|
+
# Released under the same terms as Sensu (the MIT license); see LICENSE
|
11
|
+
# for details.
|
12
|
+
#
|
13
|
+
# USING INI ARGUMENT
|
14
|
+
# This was implemented to load mysql credentials without parsing the username/password.
|
15
|
+
# The ini file should be readable by the sensu user/group.
|
16
|
+
# Ref: http://eric.lubow.org/2009/ruby/parsing-ini-files-with-ruby/
|
17
|
+
#
|
18
|
+
# EXAMPLE
|
19
|
+
# mysql-alive.rb -h db01 --ini '/etc/sensu/my.cnf'
|
20
|
+
# mysql-alive.rb -h db01 --ini '/etc/sensu/my.cnf' --ini-section customsection
|
21
|
+
#
|
22
|
+
# MY.CNF INI FORMAT
|
23
|
+
# [client]
|
24
|
+
# user=sensu
|
25
|
+
# password="abcd1234"
|
26
|
+
#
|
27
|
+
# [customsection]
|
28
|
+
# user=user
|
29
|
+
# password="password"
|
30
|
+
#
|
31
|
+
|
32
|
+
require 'sensu-plugin/check/cli'
|
33
|
+
require 'mysql'
|
34
|
+
require 'inifile'
|
35
|
+
|
36
|
+
class CheckMysqlReplicationStatus < Sensu::Plugin::Check::CLI
|
37
|
+
option :host,
|
38
|
+
short: '-h',
|
39
|
+
long: '--host=VALUE',
|
40
|
+
description: 'Database host'
|
41
|
+
|
42
|
+
option :port,
|
43
|
+
short: '-P',
|
44
|
+
long: '--port=VALUE',
|
45
|
+
description: 'Database port',
|
46
|
+
default: 3306,
|
47
|
+
# #YELLOW
|
48
|
+
proc: lambda { |s| s.to_i } # rubocop:disable Style/Lambda
|
49
|
+
|
50
|
+
option :socket,
|
51
|
+
short: '-s SOCKET',
|
52
|
+
long: '--socket SOCKET',
|
53
|
+
description: 'Socket to use'
|
54
|
+
|
55
|
+
option :user,
|
56
|
+
short: '-u',
|
57
|
+
long: '--username=VALUE',
|
58
|
+
description: 'Database username'
|
59
|
+
|
60
|
+
option :pass,
|
61
|
+
short: '-p',
|
62
|
+
long: '--password=VALUE',
|
63
|
+
description: 'Database password'
|
64
|
+
|
65
|
+
option :master_connection,
|
66
|
+
short: '-m',
|
67
|
+
long: '--master-connection=VALUE',
|
68
|
+
description: 'Replication master connection name'
|
69
|
+
|
70
|
+
option :ini,
|
71
|
+
short: '-i',
|
72
|
+
long: '--ini VALUE',
|
73
|
+
description: 'My.cnf ini file'
|
74
|
+
|
75
|
+
option :ini_section,
|
76
|
+
description: 'Section in my.cnf ini file',
|
77
|
+
long: '--ini-section VALUE',
|
78
|
+
default: 'client'
|
79
|
+
|
80
|
+
option :warn,
|
81
|
+
short: '-w',
|
82
|
+
long: '--warning=VALUE',
|
83
|
+
description: 'Warning threshold for replication lag',
|
84
|
+
default: 900,
|
85
|
+
# #YELLOW
|
86
|
+
proc: lambda { |s| s.to_i } # rubocop:disable Style/Lambda
|
87
|
+
|
88
|
+
option :crit,
|
89
|
+
short: '-c',
|
90
|
+
long: '--critical=VALUE',
|
91
|
+
description: 'Critical threshold for replication lag',
|
92
|
+
default: 1800,
|
93
|
+
# #YELLOW
|
94
|
+
proc: lambda { |s| s.to_i } # rubocop:disable Style/Lambda
|
95
|
+
|
96
|
+
def detect_replication_status?(row)
|
97
|
+
%w[
|
98
|
+
Slave_IO_State
|
99
|
+
Slave_IO_Running
|
100
|
+
Slave_SQL_Running
|
101
|
+
Last_IO_Error
|
102
|
+
Last_SQL_Error
|
103
|
+
Seconds_Behind_Master
|
104
|
+
].all? { |key| row.key? key }
|
105
|
+
end
|
106
|
+
|
107
|
+
def slave_running?(row)
|
108
|
+
%w[
|
109
|
+
Slave_IO_Running
|
110
|
+
Slave_SQL_Running
|
111
|
+
].all? { |key| row[key] =~ /Yes/ }
|
112
|
+
end
|
113
|
+
|
114
|
+
def run
|
115
|
+
if config[:ini]
|
116
|
+
ini = IniFile.load(config[:ini])
|
117
|
+
section = ini[config[:ini_section]]
|
118
|
+
db_user = section['user']
|
119
|
+
db_pass = section['password']
|
120
|
+
else
|
121
|
+
db_user = config[:user]
|
122
|
+
db_pass = config[:pass]
|
123
|
+
end
|
124
|
+
db_host = config[:host]
|
125
|
+
db_conn = config[:master_connection]
|
126
|
+
|
127
|
+
if [db_host, db_user, db_pass].any?(&:nil?)
|
128
|
+
unknown 'Must specify host, user, password'
|
129
|
+
end
|
130
|
+
|
131
|
+
begin
|
132
|
+
db = Mysql.new(db_host, db_user, db_pass, nil, config[:port], config[:socket])
|
133
|
+
|
134
|
+
results = if db_conn.nil?
|
135
|
+
db.query 'SHOW SLAVE STATUS'
|
136
|
+
else
|
137
|
+
db.query "SHOW SLAVE '#{db_conn}' STATUS"
|
138
|
+
end
|
139
|
+
|
140
|
+
unless results.nil?
|
141
|
+
results.each_hash do |row|
|
142
|
+
warn "couldn't detect replication status" unless detect_replication_status?(row)
|
143
|
+
|
144
|
+
slave_running = slave_running?(row)
|
145
|
+
|
146
|
+
output = if db_conn.nil?
|
147
|
+
'Slave not running!'
|
148
|
+
else
|
149
|
+
"Slave on master connection #{db_conn} not running!"
|
150
|
+
end
|
151
|
+
|
152
|
+
output += ' STATES:'
|
153
|
+
output += " Slave_IO_Running=#{row['Slave_IO_Running']}"
|
154
|
+
output += ", Slave_SQL_Running=#{row['Slave_SQL_Running']}"
|
155
|
+
output += ", LAST ERROR: #{row['Last_SQL_Error']}"
|
156
|
+
|
157
|
+
critical output unless slave_running
|
158
|
+
|
159
|
+
replication_delay = row['Seconds_Behind_Master'].to_i
|
160
|
+
|
161
|
+
message = "replication delayed by #{replication_delay}"
|
162
|
+
|
163
|
+
if replication_delay > config[:warn] &&
|
164
|
+
replication_delay <= config[:crit]
|
165
|
+
warning message
|
166
|
+
elsif replication_delay >= config[:crit]
|
167
|
+
critical message
|
168
|
+
elsif db_conn.nil?
|
169
|
+
ok "slave running: #{slave_running}, #{message}"
|
170
|
+
else
|
171
|
+
ok "master connection: #{db_conn}, slave running: #{slave_running}, #{message}"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
ok 'show slave status was nil. This server is not a slave.'
|
175
|
+
end
|
176
|
+
rescue Mysql::Error => e
|
177
|
+
errstr = "Error code: #{e.errno} Error message: #{e.error}"
|
178
|
+
critical "#{errstr} SQLSTATE: #{e.sqlstate}" if e.respond_to?('sqlstate')
|
179
|
+
rescue StandardError => e
|
180
|
+
critical e
|
181
|
+
ensure
|
182
|
+
db.close if db
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|