sensu-plugins-mysql-nagyt 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,175 @@
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 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 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 Lambda
95
+
96
+ def run
97
+ if config[:ini]
98
+ ini = IniFile.load(config[:ini])
99
+ section = ini[config[:ini_section]]
100
+ db_user = section['user']
101
+ db_pass = section['password']
102
+ else
103
+ db_user = config[:user]
104
+ db_pass = config[:pass]
105
+ end
106
+ db_host = config[:host]
107
+ db_conn = config[:master_connection]
108
+
109
+ if [db_host, db_user, db_pass].any?(&:nil?)
110
+ unknown 'Must specify host, user, password'
111
+ end
112
+
113
+ begin
114
+ db = Mysql.new(db_host, db_user, db_pass, nil, config[:port], config[:socket])
115
+
116
+ results = if db_conn.nil?
117
+ db.query 'SHOW SLAVE STATUS'
118
+ else
119
+ db.query "SHOW SLAVE '#{db_conn}' STATUS"
120
+ end
121
+
122
+ unless results.nil?
123
+ results.each_hash do |row|
124
+ warn "couldn't detect replication status" unless
125
+ %w(Slave_IO_State Slave_IO_Running Slave_SQL_Running Last_IO_Error Last_SQL_Error Seconds_Behind_Master).all? do |key|
126
+ row.key? key
127
+ end
128
+
129
+ slave_running = %w(Slave_IO_Running Slave_SQL_Running).all? do |key|
130
+ row[key] =~ /Yes/
131
+ end
132
+
133
+ output = if db_conn.nil?
134
+ 'Slave not running!'
135
+ else
136
+ "Slave on master connection #{db_conn} not running!"
137
+ end
138
+
139
+ output += ' STATES:'
140
+ output += " Slave_IO_Running=#{row['Slave_IO_Running']}"
141
+ output += ", Slave_SQL_Running=#{row['Slave_SQL_Running']}"
142
+ output += ", LAST ERROR: #{row['Last_SQL_Error']}"
143
+
144
+ critical output unless slave_running
145
+
146
+ replication_delay = row['Seconds_Behind_Master'].to_i
147
+
148
+ message = "replication delayed by #{replication_delay}"
149
+
150
+ if replication_delay > config[:warn] &&
151
+ replication_delay <= config[:crit]
152
+ warning message
153
+ elsif replication_delay >= config[:crit]
154
+ critical message
155
+ elsif db_conn.nil?
156
+ ok "slave running: #{slave_running}, #{message}"
157
+ else
158
+ ok "master connection: #{db_conn}, slave running: #{slave_running}, #{message}"
159
+ end
160
+ end
161
+ ok 'show slave status was nil. This server is not a slave.'
162
+ end
163
+
164
+ rescue Mysql::Error => e
165
+ errstr = "Error code: #{e.errno} Error message: #{e.error}"
166
+ critical "#{errstr} SQLSTATE: #{e.sqlstate}" if e.respond_to?('sqlstate')
167
+
168
+ rescue => e
169
+ critical e
170
+
171
+ ensure
172
+ db.close if db
173
+ end
174
+ end
175
+ end
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # MySQL Select Count Check
4
+ #
5
+ # Checks the length of a result set from a MySQL query.
6
+ #
7
+ # Copyright 2017 Andrew Thal <athal7@me.com> to check-mysql-query-result-count.rb
8
+ # Modified by Mutsutoshi Yoshimoto <negachov@gmail.com> 2018 to select count(*) version
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 MysqlSelectCountCheck < Sensu::Plugin::Check::CLI
18
+ option :host,
19
+ short: '-h HOST',
20
+ long: '--host HOST',
21
+ description: 'MySQL Host to connect to',
22
+ required: true
23
+
24
+ option :port,
25
+ short: '-P PORT',
26
+ long: '--port PORT',
27
+ description: 'MySQL Port to connect to',
28
+ proc: proc(&:to_i),
29
+ default: 3306
30
+
31
+ option :username,
32
+ short: '-u USERNAME',
33
+ long: '--user USERNAME',
34
+ description: 'MySQL Username'
35
+
36
+ option :password,
37
+ short: '-p PASSWORD',
38
+ long: '--pass PASSWORD',
39
+ description: 'MySQL password'
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: 'Warning when query value exceeds threshold',
66
+ proc: proc(&:to_i),
67
+ required: true
68
+
69
+ option :crit,
70
+ short: '-c COUNT',
71
+ long: '--critical COUNT',
72
+ description: 'Critical when query value exceeds threshold',
73
+ proc: proc(&:to_i),
74
+ required: true
75
+
76
+ option :query,
77
+ short: '-q SELECT_COUNT_QUERY',
78
+ long: '--query SELECT_COUNT_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
+ raise "invalid query : #{config[:query]}" unless config[:query] =~ /^select\s+count\(\s*\*\s*\)/i
93
+
94
+ db = Mysql.real_connect(config[:host], db_user, db_pass, config[:database], config[:port], config[:socket])
95
+
96
+ count = db.query(config[:query]).fetch_row[0].to_i
97
+ if count >= config[:crit]
98
+ critical "Count is above the CRITICAL limit: #{count} count / #{config[:crit]} limit"
99
+ elsif count >= config[:warn]
100
+ warning "Count is above the WARNING limit: #{count} count / #{config[:warn]} limit"
101
+ else
102
+ ok "Count is below thresholds : #{count} count"
103
+ end
104
+
105
+ rescue Mysql::Error => e
106
+ errstr = "Error code: #{e.errno} Error message: #{e.error}"
107
+ critical "#{errstr} SQLSTATE: #{e.sqlstate}" if e.respond_to?('sqlstate')
108
+
109
+ rescue StandardError => e
110
+ critical "unhandled exception: #{e}"
111
+
112
+ ensure
113
+ db.close if db
114
+ end
115
+ end
@@ -0,0 +1,209 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # MySQL Status Plugin
4
+ # ===
5
+ #
6
+ # This plugin attempts to login to mysql with provided credentials.
7
+ # NO DEPENDENCIES (no mysql-devel and thus no implicit mysql-server restart)
8
+ # It checks whether MySQL is UP --check status
9
+ # It checks replication delay --check replication
10
+ # Author: Magic Online - www.magic.fr
11
+ # Date: September 2016
12
+ #
13
+ # Author: Magic Online - www.magic.fr - September 2016
14
+ # Released under the same terms as Sensu (the MIT license); see LICENSE
15
+ # for details.
16
+ #
17
+ # USING INI ARGUMENT
18
+ # The ini file should be readable by the sensu user/group.
19
+ #
20
+ # EXAMPLE
21
+ # check-mysql-status.rb -h localhost --ini '/etc/sensu/my.cnf' --check status
22
+ # check-mysql-status.rb -h localhost --ini '/etc/sensu/my.cnf' --check replication
23
+ #
24
+ # MY.CNF INI FORMAT
25
+ # [client]
26
+ # user=sensu
27
+ # password="abcd1234"
28
+ # socket="/var/lib/mysql/mysql.sock"
29
+ #
30
+
31
+ require 'sensu-plugin/check/cli'
32
+ require 'inifile'
33
+ require 'open3'
34
+
35
+ # Check MySQL Status
36
+ class CheckMySQLStatus < Sensu::Plugin::Check::CLI
37
+ option :user,
38
+ description: 'MySQL User, you really should use ini to hide credentials instead of using me',
39
+ short: '-u USER',
40
+ long: '--user USER',
41
+ default: 'mosim'
42
+
43
+ option :password,
44
+ description: 'MySQL Password, you really should use ini to hide credentials instead of using me',
45
+ short: '-p PASS',
46
+ long: '--password PASS',
47
+ default: 'mysqlPassWord'
48
+
49
+ option :ini,
50
+ description: 'My.cnf ini file',
51
+ short: '-i',
52
+ long: '--ini VALUE'
53
+
54
+ option :ini_section,
55
+ description: 'Section in my.cnf ini file',
56
+ long: '--ini-section VALUE',
57
+ default: 'client'
58
+
59
+ option :hostname,
60
+ description: 'Hostname to login to',
61
+ short: '-h HOST',
62
+ long: '--hostname HOST',
63
+ default: 'localhost'
64
+
65
+ option :database,
66
+ description: 'Database schema to connect to',
67
+ short: '-d DATABASE',
68
+ long: '--database DATABASE',
69
+ default: 'test'
70
+
71
+ option :port,
72
+ description: 'Port to connect to',
73
+ short: '-P PORT',
74
+ long: '--port PORT',
75
+ default: '3306'
76
+
77
+ option :socket,
78
+ description: 'Socket to use',
79
+ short: '-s SOCKET',
80
+ long: '--socket SOCKET',
81
+ default: '/var/run/mysqld/mysqld.sock'
82
+
83
+ option :binary,
84
+ description: 'Absolute path to mysql binary',
85
+ short: '-b BINARY',
86
+ long: '--binary BINARY',
87
+ default: 'mysql'
88
+
89
+ option :check,
90
+ description: 'type of check: (status|replication)',
91
+ short: '-C CHECK',
92
+ long: '--check CHECK',
93
+ default: 'status'
94
+
95
+ option :warn,
96
+ description: 'Warning threshold for replication lag',
97
+ short: '-w',
98
+ long: '--warning=VALUE',
99
+ default: 900
100
+
101
+ option :crit,
102
+ description: 'Critical threshold for replication lag',
103
+ short: '-c',
104
+ long: '--critical=VALUE',
105
+ default: 1800
106
+
107
+ option :debug,
108
+ description: 'Print debug info',
109
+ long: '--debug',
110
+ default: false
111
+
112
+ def credentials
113
+ if config[:ini]
114
+ ini = IniFile.load(config[:ini])
115
+ section = ini[config[:ini_section]]
116
+ db_user = section['user']
117
+ db_pass = section['password']
118
+ db_socket = if config[:socket]
119
+ config[:socket]
120
+ else
121
+ section['socket']
122
+ end
123
+ else
124
+ db_user = config[:user]
125
+ db_pass = config[:password]
126
+ db_socket = config[:socket]
127
+ end
128
+ [db_user, db_pass, db_socket]
129
+ end
130
+
131
+ # Status check
132
+ def status_check(db_user, db_pass, db_socket)
133
+ cmd = "#{config[:binary]} -u #{db_user} -h #{config[:hostname]} --port #{config[:port]} \
134
+ --socket #{db_socket} -p\"#{db_pass.strip}\" --batch --disable-column-names -e 'show schemas;'"
135
+ begin
136
+ stdout, _stderr, status = Open3.capture3(cmd)
137
+ if status.to_i == 0
138
+ ok "#{status} | #{stdout.split("\n")}"
139
+ else
140
+ critical "Error message: status: #{status}"
141
+ end
142
+ rescue => e
143
+ critical "Error message: status: #{status} | Exception: #{e}"
144
+ ensure
145
+ puts ''
146
+ end
147
+ end
148
+
149
+ def replication_check(db_user, db_pass, db_socket)
150
+ table = {}
151
+ begin
152
+ cmd = "#{config[:binary]} -u #{db_user} -h #{config[:hostname]} --port #{config[:port]} \
153
+ --socket #{db_socket} -p\"#{db_pass.strip}\" -e 'SHOW SLAVE STATUS\\G'"
154
+ stdout, _stderr, status = Open3.capture3(cmd)
155
+ if status.to_i != 0
156
+ critical "Error message: status: #{status}"
157
+ end
158
+ stdout.split("\n").each do |line|
159
+ key = line.split(':')[0]
160
+ value = line.split(':')[1]
161
+ table[key.strip.to_s] = value.to_s unless key.include? '***'
162
+ end
163
+ dict = []
164
+ table.keys.to_a.each do |k|
165
+ %w(Slave_IO_State Slave_IO_Running Slave_SQL_Running Last_IO_Error Last_SQL_Error Seconds_Behind_Master).each do |key|
166
+ dict.push(k.strip.to_s) if key.strip == k.strip
167
+ end
168
+ end
169
+ table.each do |attribute, value|
170
+ puts "#{attribute} : #{value}" if config[:debug]
171
+ warn "couldn't detect replication status :#{dict.size}" unless dict.size == 6
172
+ slave_running = %w(Slave_IO_Running Slave_SQL_Running).all? do |key|
173
+ table[key].to_s =~ /Yes/
174
+ end
175
+ output = 'Slave not running!'
176
+ output += ' STATES:'
177
+ output += " Slave_IO_Running=#{table['Slave_IO_Running']}"
178
+ output += ", Slave_SQL_Running=#{table['Slave_SQL_Running']}"
179
+ output += ", LAST ERROR: #{table['Last_SQL_Error']}"
180
+ critical output unless slave_running
181
+ replication_delay = table['Seconds_Behind_Master'].to_i
182
+ message = "replication delayed by #{replication_delay}"
183
+ if replication_delay > config[:warn].to_i && replication_delay <= config[:crit].to_i
184
+ warning message
185
+ elsif replication_delay >= config[:crit].to_i
186
+ critical message
187
+ else
188
+ ok "slave running: #{slave_running}, #{message}"
189
+ end
190
+ end
191
+ ok 'show slave status was nil. This server is not a slave.'
192
+ rescue => e
193
+ critical "Error message: status: #{status} | Exception: #{e}"
194
+ end
195
+ end
196
+
197
+ def run
198
+ db_user = credentials[0]
199
+ db_pass = credentials[1]
200
+ db_socket = credentials[2]
201
+ if config[:check] == 'status'
202
+ status_check(db_user, db_pass, db_socket)
203
+ end
204
+ if config[:check] == 'replication'
205
+ replication_check(db_user, db_pass, db_socket)
206
+ end
207
+ unknown 'No check type succeeded. Check your options'
208
+ end
209
+ end