sensu-plugins-mysql-nagyt 2.6.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.
@@ -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