mysql_health 0.5.6 → 0.5.7
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/mysql_health/command_line.rb +13 -3
- data/lib/mysql_health/health.rb +72 -25
- data/lib/mysql_health/version.rb +1 -1
- data/redhat/rubygem-mysql_health.spec +1 -1
- metadata +3 -3
@@ -65,11 +65,21 @@ module MysqlHealth
|
|
65
65
|
@options[:check][:slave] = true
|
66
66
|
end
|
67
67
|
|
68
|
+
@options[:check][:database] = nil
|
69
|
+
opts.on( '--check:database NAME', 'Ensure that database exists') do |name|
|
70
|
+
@options[:check][:database] = name
|
71
|
+
end
|
72
|
+
|
68
73
|
@options[:check][:allow_overlapping] = false
|
69
74
|
opts.on( '--check:allow-overlapping', "Allow overlapping health checks (default: #{@options[:check][:allow_overlapping]})") do
|
70
75
|
@options[:check][:allow_overlapping] = true
|
71
76
|
end
|
72
77
|
|
78
|
+
@options[:check][:allow_master] = false
|
79
|
+
opts.on( '--check:allow-master', "Allow master to act as slave when --check:slave is used (default: #{@options[:check][:allow_master]})") do
|
80
|
+
@options[:check][:allow_master] = true
|
81
|
+
end
|
82
|
+
|
73
83
|
@options[:check][:interval] = '10s'
|
74
84
|
opts.on( '--check:interval INTERVAL', "Check health every INTERVAL (default: #{@options[:check][:interval]})") do |interval|
|
75
85
|
@options[:check][:interval] = interval.to_s
|
@@ -77,7 +87,7 @@ module MysqlHealth
|
|
77
87
|
|
78
88
|
@options[:check][:delay] = '0s'
|
79
89
|
opts.on( '--check:delay DELAY', "Delay health checks for INTERVAL (default: #{@options[:check][:delay]})") do |delay|
|
80
|
-
@options[:check][:delay] =
|
90
|
+
@options[:check][:delay] = delay.to_s
|
81
91
|
end
|
82
92
|
|
83
93
|
@options[:check][:dsn] ||= "DBI:Mysql:mysql:localhost"
|
@@ -92,13 +102,13 @@ module MysqlHealth
|
|
92
102
|
|
93
103
|
@options[:check][:password] ||= ""
|
94
104
|
opts.on( '--check:password PASSWORD', "MySQL Password (default: #{@options[:check][:password]})") do |password|
|
95
|
-
@options[:check][:password] =
|
105
|
+
@options[:check][:password] = password.to_s
|
96
106
|
end
|
97
107
|
|
98
108
|
# Server
|
99
109
|
@options[:server][:listen] = '0.0.0.0'
|
100
110
|
opts.on( '-l', '--server:listen ADDR', "Server listen address (default: #{@options[:server][:listen]})") do |addr|
|
101
|
-
@options[:server][:addr] =
|
111
|
+
@options[:server][:addr] = addr.to_s
|
102
112
|
end
|
103
113
|
|
104
114
|
@options[:server][:port] = 3305
|
data/lib/mysql_health/health.rb
CHANGED
@@ -71,7 +71,7 @@ module MysqlHealth
|
|
71
71
|
|
72
72
|
def master_status=(response)
|
73
73
|
@mutex.synchronize do
|
74
|
-
MysqlHealth.log.info("master status: #{response[:status]}")
|
74
|
+
MysqlHealth.log.info("master status: #{response[:status]} (#{response[:content].split(/\n/)[0]})")
|
75
75
|
@master_status = response
|
76
76
|
end
|
77
77
|
end
|
@@ -86,7 +86,7 @@ module MysqlHealth
|
|
86
86
|
|
87
87
|
def slave_status=(response)
|
88
88
|
@mutex.synchronize do
|
89
|
-
MysqlHealth.log.info("slave status: #{response[:status]}")
|
89
|
+
MysqlHealth.log.info("slave status: #{response[:status]} (#{response[:content].split(/\n/)[0]})")
|
90
90
|
@slave_status = response
|
91
91
|
end
|
92
92
|
end
|
@@ -104,6 +104,10 @@ module MysqlHealth
|
|
104
104
|
return (variables.length == 1)
|
105
105
|
end
|
106
106
|
|
107
|
+
def master?(dbh)
|
108
|
+
read_only?(dbh) == false
|
109
|
+
end
|
110
|
+
|
107
111
|
def check_master
|
108
112
|
MysqlHealth.log.debug("check_master")
|
109
113
|
response = {}
|
@@ -113,23 +117,25 @@ module MysqlHealth
|
|
113
117
|
# connect to the MySQL server
|
114
118
|
dbh = DBI.connect(@options[:dsn], @options[:username], @options[:password])
|
115
119
|
|
116
|
-
|
117
|
-
|
118
|
-
|
120
|
+
# Validate that database exists
|
121
|
+
unless @options[:database].nil?
|
122
|
+
unless database?(dbh, @options[:database])
|
123
|
+
raise Exception.new("Database schema named #{@options[:database]} does not exist")
|
124
|
+
end
|
119
125
|
end
|
120
|
-
|
121
|
-
|
126
|
+
|
127
|
+
status = show_status(dbh)
|
122
128
|
if status.length > 0
|
123
129
|
if read_only?(dbh)
|
124
130
|
response[:status] = '503 Service Read Only'
|
125
|
-
response[:content] =
|
131
|
+
response[:content] = describe_status(status)
|
126
132
|
else
|
127
133
|
response[:status] = '200 OK'
|
128
|
-
response[:content] =
|
134
|
+
response[:content] = describe_status(status)
|
129
135
|
end
|
130
136
|
else
|
131
137
|
response[:status] = '503 Service Unavailable'
|
132
|
-
response[:content] =
|
138
|
+
response[:content] = describe_status(status)
|
133
139
|
end
|
134
140
|
rescue Exception => e
|
135
141
|
response[:status] = '500 Server Error'
|
@@ -138,6 +144,46 @@ module MysqlHealth
|
|
138
144
|
self.master_status=(response)
|
139
145
|
end
|
140
146
|
|
147
|
+
def describe_status(status)
|
148
|
+
# Mimick "mysqladmin status"
|
149
|
+
"Uptime: %s Threads: %s Questions: %s Slow queries: %s Opens: %s Flush tables: %s Open tables: %s Queries per second avg: %.3f\n" %
|
150
|
+
[ status[:uptime], status[:threads_running], status[:questions], status[:slow_queries], status[:opened_tables], status[:flush_commands], status[:open_tables], status[:queries].to_i/status[:uptime].to_i]
|
151
|
+
end
|
152
|
+
|
153
|
+
# Return a hash of status information
|
154
|
+
def show_status(dbh, type = nil)
|
155
|
+
status = {}
|
156
|
+
if type.nil?
|
157
|
+
# Format of "SHOW STATUS" differs from "SHOW [MASTER|SLAVE] STATUS"
|
158
|
+
dbh.select_all('SHOW STATUS') do |row|
|
159
|
+
status[row[0].downcase.to_sym] = row[1]
|
160
|
+
end
|
161
|
+
else
|
162
|
+
dbh.execute('SHOW %s STATUS' % type.to_s.upcase) do |sth|
|
163
|
+
sth.fetch_hash() do |row|
|
164
|
+
row.each_pair do |k,v|
|
165
|
+
status[k.downcase.to_sym] = v
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
status
|
171
|
+
end
|
172
|
+
|
173
|
+
def show_create_database(dbh, name)
|
174
|
+
schema = nil
|
175
|
+
dbh.execute('SHOW CREATE DATABASE %s' % name) do |sth|
|
176
|
+
sth.fetch() do |row|
|
177
|
+
schema = row[1]
|
178
|
+
end
|
179
|
+
end
|
180
|
+
return schema
|
181
|
+
end
|
182
|
+
|
183
|
+
def database?(dbh, name)
|
184
|
+
show_create_database(dbh, name).nil? == false
|
185
|
+
end
|
186
|
+
|
141
187
|
def check_slave
|
142
188
|
MysqlHealth.log.debug("check_slave")
|
143
189
|
response = {}
|
@@ -147,41 +193,42 @@ module MysqlHealth
|
|
147
193
|
# connect to the MySQL server
|
148
194
|
dbh = DBI.connect(@options[:dsn], @options[:username], @options[:password])
|
149
195
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
row.each_pair do |k,v|
|
155
|
-
status[k.downcase.to_sym] = v
|
156
|
-
show_slave_status << "#{k}: #{v}"
|
157
|
-
end
|
196
|
+
# Validate that database exists
|
197
|
+
unless @options[:database].nil?
|
198
|
+
unless database?(dbh, @options[:database])
|
199
|
+
raise Exception.new("Database schema named #{@options[:database]} does not exist")
|
158
200
|
end
|
159
201
|
end
|
160
202
|
|
161
|
-
|
162
|
-
|
203
|
+
show_slave_status = show_status(dbh, :slave)
|
204
|
+
if show_slave_status.length > 0
|
205
|
+
seconds_behind_master = show_slave_status[:seconds_behind_master]
|
163
206
|
|
164
207
|
# We return a "203 Non-Authoritative Information" when replication is shot. We don't want to reduce site performance, but still want to track that something is awry.
|
165
208
|
if seconds_behind_master.eql?('NULL')
|
166
209
|
response[:status] = '203 Slave Stopped'
|
167
|
-
response[:content] =
|
210
|
+
response[:content] = show_slave_status.to_json
|
168
211
|
response[:content_type] = 'application/json'
|
169
212
|
elsif seconds_behind_master.to_i > 60*30
|
170
213
|
response[:status] = '203 Slave Behind'
|
171
|
-
response[:content] =
|
214
|
+
response[:content] = show_slave_status.to_json
|
172
215
|
response[:content_type] = 'application/json'
|
173
216
|
elsif read_only?(dbh)
|
174
217
|
response[:status] = '200 OK ' + seconds_behind_master + ' Seconds Behind Master'
|
175
|
-
response[:content] =
|
218
|
+
response[:content] = show_slave_status.to_json
|
176
219
|
response[:content_type] = 'application/json'
|
177
220
|
else
|
178
221
|
response[:status] = '503 Service Unavailable'
|
179
|
-
response[:content] =
|
222
|
+
response[:content] = show_slave_status.to_json
|
180
223
|
response[:content_type] = 'application/json'
|
181
224
|
end
|
225
|
+
elsif @options[:allow_master] && master?(dbh)
|
226
|
+
response[:status] = '200 OK Master Running'
|
227
|
+
response[:content] = describe_status show_status(dbh)
|
228
|
+
response[:content_type] = 'application/json'
|
182
229
|
else
|
183
230
|
response[:status] = '503 Slave Not Configured'
|
184
|
-
response[:content] = show_slave_status.
|
231
|
+
response[:content] = show_slave_status.to_json
|
185
232
|
end
|
186
233
|
rescue Exception => e
|
187
234
|
response[:status] = '500 Server Error'
|
data/lib/mysql_health/version.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
%define ruby_sitelib %(ruby -rrbconfig -e "puts Config::CONFIG['sitelibdir']")
|
2
2
|
%define gemdir %(ruby -rubygems -e 'puts Gem::dir' 2>/dev/null)
|
3
3
|
%define gemname mysql_health
|
4
|
-
%define gemversion 0.5.
|
4
|
+
%define gemversion 0.5.7
|
5
5
|
%define geminstdir %{gemdir}/gems/%{gemname}-%{gemversion}
|
6
6
|
%define gemfile %{gemname}-%{gemversion}.gem
|
7
7
|
%define gemsummary %(ruby -rrubygems -e 'puts YAML.load(`gem specification %{gemfile}`).summary')
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 5
|
8
|
-
-
|
9
|
-
version: 0.5.
|
8
|
+
- 7
|
9
|
+
version: 0.5.7
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Erik Osterman
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2012-12-
|
17
|
+
date: 2012-12-06 00:00:00 -08:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|