mysql_manager 1.0.3 → 1.0.4
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.
- checksums.yaml +7 -0
- data/README.md +18 -1
- data/lib/mysql_manager/command_line.rb +38 -0
- data/lib/mysql_manager/utilities.rb +69 -0
- data/lib/mysql_manager/version.rb +1 -1
- data/mysql_manager.gemspec +1 -0
- metadata +73 -78
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7db617b7015f5a675990bef408681d12e9333c1e
|
4
|
+
data.tar.gz: 6c130b35e26811fd5defcdfba76efb38147aef0f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ee25ebbb9fc2c754fb96b5edbe9ef157e6483be8954ab928ba008a77f1491686e1e523d9fb1afa2dbae7bb18df5cb6855115e2487f782f6dc068151db7a5eaa3
|
7
|
+
data.tar.gz: cb8de0cc6774c0762e963ccbd92fa2709e8d4c13c8a4528455992299e4c11ea853aad089eb4f4a74f677ef4b32ed99bcc5612392a7ea0ea4d30a343440832ae2
|
data/README.md
CHANGED
@@ -22,7 +22,7 @@ Or install it yourself as:
|
|
22
22
|
|
23
23
|
## Usage
|
24
24
|
|
25
|
-
Usage: mysql-manager options
|
25
|
+
Usage: bin/mysql-manager options
|
26
26
|
--kill Kill queries based on specified criteria
|
27
27
|
--kill:max-query-time TIME Kill queries that have been running for more than TIME
|
28
28
|
--kill:user USER Kill queries matching USER (repeatable)
|
@@ -48,10 +48,17 @@ Or install it yourself as:
|
|
48
48
|
--log:file FILE Write logs to FILE (default: STDERR)
|
49
49
|
--log:age DAYS Rotate logs after DAYS pass (default: 7)
|
50
50
|
--log:size SIZE Rotate logs after the grow past SIZE bytes
|
51
|
+
--hotcopy Perform a hotcopy
|
52
|
+
--hotcopy:data-dir PATH Rsync mysql data dir from PATH (default: /var/lib/mysql)
|
53
|
+
--hotcopy:backup-dir PATH Rsync to PATH (default: /tmp/mysql)
|
54
|
+
--hotcopy:rsync-args ARGS Arguments to pass to rsync (default: -av)
|
55
|
+
--hotcopy:rsync-bin bin Rsync executable path (default: rsync)
|
56
|
+
--hotcopy:rsync-ttl ttl Acceptable rsync execution time before performing table locks (default: 60)
|
51
57
|
--dry-run Do not run statements which affect the state of the database when executed
|
52
58
|
-V, --version Display version information
|
53
59
|
-h, --help Display this screen
|
54
60
|
|
61
|
+
|
55
62
|
## How matching is done
|
56
63
|
|
57
64
|
If you specify a simple string as a parameter (e.g. `--kill:user api`), this is interpreted as an exactly matching
|
@@ -78,6 +85,16 @@ Reload `/etc/my.cnf` without restarting MySQL:
|
|
78
85
|
|
79
86
|
mysql-manager --reload-my-cnf --reload-my-cnf:config /etc/my.cnf --log:level DEBUG
|
80
87
|
|
88
|
+
Perform a hotcopy backup of the running mysql database using rsync to a remote server. It will repeated rsync the folder without locks until syncs take less than 30 seconds.
|
89
|
+
|
90
|
+
mysql-manager --hotcopy \
|
91
|
+
--hotcopy:data-dir /var/lib/mysql/ \
|
92
|
+
--hotcopy:backup-dir user@remote.host.com:/tmp/mysql/ \
|
93
|
+
--hotcopy:rsync-args "-av --exclude=*.err" \
|
94
|
+
--hotcopy:rsync-ttl 30 \
|
95
|
+
--db:user root \
|
96
|
+
--db:pass $MYSQL_ROOT_PASSWORD
|
97
|
+
|
81
98
|
## Contributors
|
82
99
|
|
83
100
|
https://github.com/osterman/mysql_manager/graphs/contributors
|
@@ -40,6 +40,7 @@ module MysqlManager
|
|
40
40
|
@options[:kill] = {}
|
41
41
|
@options[:reload_my_cnf] = {}
|
42
42
|
@options[:skip_replication_errors] = {}
|
43
|
+
@options[:hotcopy] = {}
|
43
44
|
|
44
45
|
begin
|
45
46
|
@optparse = OptionParser.new do |opts|
|
@@ -178,6 +179,40 @@ module MysqlManager
|
|
178
179
|
@options[:log][:size] = size.to_i
|
179
180
|
end
|
180
181
|
|
182
|
+
#
|
183
|
+
# Hotcopy
|
184
|
+
#
|
185
|
+
|
186
|
+
@options[:hotcopy][:execute] = false
|
187
|
+
opts.on( '--hotcopy', 'Perform a hotcopy') do
|
188
|
+
@options[:hotcopy][:execute] = true
|
189
|
+
end
|
190
|
+
|
191
|
+
@options[:hotcopy][:data_dir] = '/var/lib/mysql'
|
192
|
+
opts.on( '--hotcopy:data-dir PATH', "Rsync mysql data dir from PATH (default: #{@options[:hotcopy][:data_dir]})") do |path|
|
193
|
+
@options[:hotcopy][:data_dir] = path.to_s
|
194
|
+
end
|
195
|
+
|
196
|
+
@options[:hotcopy][:backup_dir] = '/tmp/mysql'
|
197
|
+
opts.on( '--hotcopy:backup-dir PATH', "Rsync to PATH (default: #{@options[:hotcopy][:backup_dir]})") do |path|
|
198
|
+
@options[:hotcopy][:backup_dir] = path.to_s
|
199
|
+
end
|
200
|
+
|
201
|
+
@options[:hotcopy][:rsync_args] = '-av'
|
202
|
+
opts.on( '--hotcopy:rsync-args ARGS', "Arguments to pass to rsync (default: #{@options[:hotcopy][:rsync_args]})") do |args|
|
203
|
+
@options[:hotcopy][:rsync_args] = Shellwords.split(args.to_s)
|
204
|
+
end
|
205
|
+
|
206
|
+
@options[:hotcopy][:rsync_bin] = 'rsync'
|
207
|
+
opts.on( '--hotcopy:rsync-bin bin', "Rsync executable path (default: #{@options[:hotcopy][:rsync_bin]})") do |bin|
|
208
|
+
@options[:hotcopy][:rsync_bin] = bin.to_s
|
209
|
+
end
|
210
|
+
|
211
|
+
@options[:hotcopy][:rsync_ttl] = 60
|
212
|
+
opts.on( '--hotcopy:rsync-ttl ttl', "Acceptable rsync execution time before performing table locks (default: #{@options[:hotcopy][:rsync_ttl]})") do |ttl|
|
213
|
+
@options[:hotcopy][:rsync_ttl] = ttl.to_i
|
214
|
+
end
|
215
|
+
|
181
216
|
#
|
182
217
|
# General options
|
183
218
|
#
|
@@ -234,6 +269,9 @@ module MysqlManager
|
|
234
269
|
when :reload_my_cnf
|
235
270
|
@log.debug("about to call reload_my_cnf")
|
236
271
|
@utilities.reload_my_cnf(options)
|
272
|
+
when :hotcopy
|
273
|
+
@log.debug("about to call hotcopy")
|
274
|
+
@utilities.hotcopy(options)
|
237
275
|
end
|
238
276
|
rescue DBI::DatabaseError => e
|
239
277
|
@log.fatal(e.message)
|
@@ -20,6 +20,8 @@
|
|
20
20
|
require 'dbi'
|
21
21
|
require 'logger'
|
22
22
|
require 'parseconfig'
|
23
|
+
require 'shellwords'
|
24
|
+
require 'open3'
|
23
25
|
|
24
26
|
module MysqlManager
|
25
27
|
class FileNotFoundException < Exception; end
|
@@ -214,5 +216,72 @@ module MysqlManager
|
|
214
216
|
@log.error("Error code: #{e.err}: #{e.errstr}")
|
215
217
|
end
|
216
218
|
end
|
219
|
+
|
220
|
+
def run(cmd)
|
221
|
+
stdout, stderr, status = Open3.capture3(Shellwords.join(cmd))
|
222
|
+
if status != 0
|
223
|
+
puts stderr
|
224
|
+
raise Exception.new("execution of command failed")
|
225
|
+
end
|
226
|
+
return status
|
227
|
+
end
|
228
|
+
|
229
|
+
def hotcopy(options = {})
|
230
|
+
begin
|
231
|
+
t_start = Time.now.to_f
|
232
|
+
# ensure mysql directory exists
|
233
|
+
unless File.directory?(options[:data_dir])
|
234
|
+
raise FileNotFoundException.new("Unable to open mysql data dir #{options[:data_dir]}")
|
235
|
+
end
|
236
|
+
|
237
|
+
rsync = []
|
238
|
+
rsync << options[:rsync_bin]
|
239
|
+
rsync << options[:rsync_args]
|
240
|
+
rsync << options[:data_dir] + '/'
|
241
|
+
rsync << options[:backup_dir] + '/'
|
242
|
+
|
243
|
+
# create target directory if it does not already exist
|
244
|
+
unless File.directory?(options[:backup_dir])
|
245
|
+
@log.info("Creating #{options[:backup_dir]}")
|
246
|
+
run ['mkdir', '-p', options[:backup_dir]]
|
247
|
+
end
|
248
|
+
|
249
|
+
rsync.flatten!
|
250
|
+
|
251
|
+
t_rsync = Time.now.to_f
|
252
|
+
t_rsync_elapsed = Time.now.to_f
|
253
|
+
while t_rsync_elapsed > options[:rsync_ttl]
|
254
|
+
# first do a raw rsync without table locks
|
255
|
+
@log.info("Performing first-pass rsync without table locks")
|
256
|
+
run rsync
|
257
|
+
t_rsync_elapsed = Time.now.to_f - t_rsync
|
258
|
+
@log.info("Rsync took #{t_rsync_elapsed} seconds")
|
259
|
+
sleep 1
|
260
|
+
t_rsync = Time.now.to_f
|
261
|
+
end
|
262
|
+
|
263
|
+
# then flush tables with read lock
|
264
|
+
@log.info("Locking tables")
|
265
|
+
t_lock = Time.now.to_f
|
266
|
+
@dbh.do("FLUSH TABLES WITH READ LOCK") unless @dry_run
|
267
|
+
|
268
|
+
# re-sync the delats
|
269
|
+
@log.info("Performing second-pass rsync with table locks")
|
270
|
+
run rsync
|
271
|
+
|
272
|
+
# release locks
|
273
|
+
@log.info("Unlocking tables")
|
274
|
+
@dbh.do('UNLOCK TABLES')
|
275
|
+
@log.info("Total lock time #{Time.now.to_f - t_lock} seconds")
|
276
|
+
@log.info("Total elapsed time #{Time.now.to_f - t_start} seconds")
|
277
|
+
|
278
|
+
rescue DBI::DatabaseError => e
|
279
|
+
@log.debug(@dbh.last_statement)
|
280
|
+
@log.warn(e.message)
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
|
285
|
+
|
217
286
|
end
|
218
287
|
end
|
data/mysql_manager.gemspec
CHANGED
@@ -16,6 +16,7 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.require_paths = ["lib"]
|
17
17
|
gem.version = MysqlManager::VERSION
|
18
18
|
gem.add_runtime_dependency "parseconfig", ">= 1.0.2"
|
19
|
+
gem.add_runtime_dependency "mysql2", ">= 0.3.18"
|
19
20
|
gem.add_runtime_dependency "dbi", ">= 0.4.5"
|
20
21
|
gem.add_runtime_dependency "dbd-mysql", ">= 0.4.4"
|
21
22
|
end
|
metadata
CHANGED
@@ -1,77 +1,79 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: mysql_manager
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
segments:
|
6
|
-
- 1
|
7
|
-
- 0
|
8
|
-
- 3
|
9
|
-
version: 1.0.3
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.4
|
10
5
|
platform: ruby
|
11
|
-
authors:
|
6
|
+
authors:
|
12
7
|
- Erik Osterman
|
13
8
|
autorequire:
|
14
9
|
bindir: bin
|
15
10
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
dependencies:
|
20
|
-
- !ruby/object:Gem::Dependency
|
11
|
+
date: 2015-05-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
21
14
|
name: parseconfig
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.0.2
|
20
|
+
type: :runtime
|
22
21
|
prerelease: false
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
- !ruby/object:Gem::Version
|
28
|
-
segments:
|
29
|
-
- 1
|
30
|
-
- 0
|
31
|
-
- 2
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
32
26
|
version: 1.0.2
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: mysql2
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.3.18
|
33
34
|
type: :runtime
|
34
|
-
version_requirements: *id001
|
35
|
-
- !ruby/object:Gem::Dependency
|
36
|
-
name: dbi
|
37
35
|
prerelease: false
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.3.18
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: dbi
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
47
|
version: 0.4.5
|
48
48
|
type: :runtime
|
49
|
-
version_requirements: *id002
|
50
|
-
- !ruby/object:Gem::Dependency
|
51
|
-
name: dbd-mysql
|
52
49
|
prerelease: false
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.4.5
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: dbd-mysql
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
62
61
|
version: 0.4.4
|
63
62
|
type: :runtime
|
64
|
-
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.4.4
|
65
69
|
description: MySQL Manager is a utility to perform routine tasks on a MySQL database.
|
66
|
-
email:
|
70
|
+
email:
|
67
71
|
- e@osterman.com
|
68
|
-
executables:
|
72
|
+
executables:
|
69
73
|
- mysql-manager
|
70
74
|
extensions: []
|
71
|
-
|
72
75
|
extra_rdoc_files: []
|
73
|
-
|
74
|
-
files:
|
76
|
+
files:
|
75
77
|
- .gitignore
|
76
78
|
- Gemfile
|
77
79
|
- LICENSE
|
@@ -83,37 +85,30 @@ files:
|
|
83
85
|
- lib/mysql_manager/utilities.rb
|
84
86
|
- lib/mysql_manager/version.rb
|
85
87
|
- mysql_manager.gemspec
|
86
|
-
has_rdoc: true
|
87
88
|
homepage: https://github.com/osterman/mysql_manager
|
88
|
-
licenses:
|
89
|
+
licenses:
|
89
90
|
- GPL3
|
91
|
+
metadata: {}
|
90
92
|
post_install_message:
|
91
93
|
rdoc_options: []
|
92
|
-
|
93
|
-
require_paths:
|
94
|
+
require_paths:
|
94
95
|
- lib
|
95
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
requirements:
|
106
|
-
- - ">="
|
107
|
-
- !ruby/object:Gem::Version
|
108
|
-
segments:
|
109
|
-
- 0
|
110
|
-
version: "0"
|
96
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - '>='
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - '>='
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
111
106
|
requirements: []
|
112
|
-
|
113
107
|
rubyforge_project:
|
114
|
-
rubygems_version:
|
108
|
+
rubygems_version: 2.0.14
|
115
109
|
signing_key:
|
116
|
-
specification_version:
|
117
|
-
summary: MySQL Manager is a utility to perform routine tasks such as restoring replication
|
110
|
+
specification_version: 4
|
111
|
+
summary: MySQL Manager is a utility to perform routine tasks such as restoring replication
|
112
|
+
after errors, killing queries based on a set of criteria, or reloading my.cnf without
|
113
|
+
restarting the database.
|
118
114
|
test_files: []
|
119
|
-
|