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.
@@ -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