mysql_health 0.5.6 → 0.5.7

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.
@@ -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] = interval.to_s
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] = interval.to_s
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] = host.to_s
111
+ @options[:server][:addr] = addr.to_s
102
112
  end
103
113
 
104
114
  @options[:server][:port] = 3305
@@ -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
- status = {}
117
- dbh.select_all('SHOW STATUS') do |row|
118
- status[row[0].downcase.to_sym] = row[1]
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
- mysqladmin_status = "Uptime: %s Threads: %s Questions: %s Slow queries: %s Opens: %s Flush tables: %s Open tables: %s Queries per second avg: %.3f\n" %
121
- [ 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]
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] = mysqladmin_status
131
+ response[:content] = describe_status(status)
126
132
  else
127
133
  response[:status] = '200 OK'
128
- response[:content] = mysqladmin_status
134
+ response[:content] = describe_status(status)
129
135
  end
130
136
  else
131
137
  response[:status] = '503 Service Unavailable'
132
- response[:content] = mysqladmin_status
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
- show_slave_status = []
151
- status = {}
152
- dbh.execute('SHOW SLAVE STATUS') do |sth|
153
- sth.fetch_hash() do |row|
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
- if status.length > 0
162
- seconds_behind_master = status[:seconds_behind_master]
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] = status.to_json
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] = status.to_json
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] = status.to_json
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] = status.to_json
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.join("\n")
231
+ response[:content] = show_slave_status.to_json
185
232
  end
186
233
  rescue Exception => e
187
234
  response[:status] = '500 Server Error'
@@ -18,5 +18,5 @@
18
18
  # along with mysql_health. If not, see <http://www.gnu.org/licenses/>.
19
19
  #
20
20
  module MysqlHealth
21
- VERSION = "0.5.6"
21
+ VERSION = "0.5.7"
22
22
  end
@@ -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.6
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
- - 6
9
- version: 0.5.6
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-05 00:00:00 -08:00
17
+ date: 2012-12-06 00:00:00 -08:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency