mysql_backup 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.rdoc +18 -0
- data/README.textile +101 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/bin/mysql_backup +6 -0
- data/bin/mysql_backup_install +7 -0
- data/lib/mysql_backup/backup.rb +65 -0
- data/lib/mysql_backup/install.rb +73 -0
- data/lib/mysql_backup/mysql_backup.yml.example +11 -0
- data/lib/mysql_backup/options.rb +24 -0
- data/lib/mysql_backup/pty.rb +32 -0
- data/lib/mysql_backup.rb +30 -0
- data/test/helper.rb +10 -0
- data/test/test_mysql_backup.rb +7 -0
- metadata +92 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Christian Hellsten
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
= mysql_backup
|
2
|
+
|
3
|
+
Description goes here.
|
4
|
+
|
5
|
+
== Note on Patches/Pull Requests
|
6
|
+
|
7
|
+
* Fork the project.
|
8
|
+
* Make your feature addition or bug fix.
|
9
|
+
* Add tests for it. This is important so I don't break it in a
|
10
|
+
future version unintentionally.
|
11
|
+
* Commit, do not mess with rakefile, version, or history.
|
12
|
+
(if you want to have your own version, that is fine but
|
13
|
+
bump version in a commit by itself I can ignore when I pull)
|
14
|
+
* Send me a pull request. Bonus points for topic branches.
|
15
|
+
|
16
|
+
== Copyright
|
17
|
+
|
18
|
+
Copyright (c) 2009 Christian Hellsten. See LICENSE for details.
|
data/README.textile
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
h1. mysql-backup
|
2
|
+
|
3
|
+
A command line tool that backups all MySQL database instances it can find a server.
|
4
|
+
|
5
|
+
h2. Installation
|
6
|
+
|
7
|
+
<pre>
|
8
|
+
<code>
|
9
|
+
$ gem sources -a http://gems.github.com (you only have to do this once)
|
10
|
+
$ sudo gem install christianhellsten-mysql-backup
|
11
|
+
</code>
|
12
|
+
</pre>
|
13
|
+
|
14
|
+
You can also grab the source code and install with rake:
|
15
|
+
<pre>
|
16
|
+
<code>
|
17
|
+
$ cd /usr/local/src
|
18
|
+
$ git clone git://github.com/christianhellsten/mysql-backup.git
|
19
|
+
$ cd mysql-backup
|
20
|
+
$ sudo rake install_gem
|
21
|
+
</code>
|
22
|
+
</pre>
|
23
|
+
|
24
|
+
h2. Configuration
|
25
|
+
|
26
|
+
Configuration is easy, just run the built-in mysql_backup_install command:
|
27
|
+
|
28
|
+
<pre>
|
29
|
+
<code>
|
30
|
+
$ sudo mysql_backup_install
|
31
|
+
</code>
|
32
|
+
</pre>
|
33
|
+
|
34
|
+
The installation script will ask you to enter all necessary information and then writes the configuration to /etc/mysql_backup.
|
35
|
+
|
36
|
+
h2. Usage
|
37
|
+
|
38
|
+
Taking a backup of all databases is also easy:
|
39
|
+
|
40
|
+
<pre>
|
41
|
+
<code>
|
42
|
+
$ sudo mysql_backup
|
43
|
+
</code>
|
44
|
+
</pre>
|
45
|
+
|
46
|
+
This will backup all databases, except the ones defined in the configuration file using the *skip* parameter.
|
47
|
+
|
48
|
+
h2. Scheduled backups with cron
|
49
|
+
|
50
|
+
Open the cron configuration with the following command:
|
51
|
+
|
52
|
+
<pre>
|
53
|
+
<code>
|
54
|
+
$ sudo crontab -e
|
55
|
+
</code>
|
56
|
+
</pre>
|
57
|
+
|
58
|
+
Add the following:
|
59
|
+
|
60
|
+
<pre>
|
61
|
+
<code>
|
62
|
+
PATH=/usr/local/bin:/usr/bin:/bin
|
63
|
+
SHELL=/bin/bash
|
64
|
+
|
65
|
+
# m h dom mon dow command
|
66
|
+
|
67
|
+
# Backup all MySQL databases every night at 24:00
|
68
|
+
|
69
|
+
00 00 * * * mysql_backup
|
70
|
+
</code>
|
71
|
+
</pre>
|
72
|
+
|
73
|
+
h2. Sample configuration
|
74
|
+
|
75
|
+
<pre>
|
76
|
+
<code>
|
77
|
+
user: root
|
78
|
+
password: xxx
|
79
|
+
host: localhost
|
80
|
+
dir: /var/backup
|
81
|
+
format: %d-%m-%y
|
82
|
+
keep: 10
|
83
|
+
|
84
|
+
mysqldump:
|
85
|
+
options: -Q -c -C --add-drop-table --add-locks --quick --lock-tables
|
86
|
+
path:
|
87
|
+
skip: [mysql, test, information_schema]
|
88
|
+
</code>
|
89
|
+
</pre>
|
90
|
+
|
91
|
+
h2. TODO
|
92
|
+
|
93
|
+
* Refactor
|
94
|
+
* List dependencies
|
95
|
+
* Handle command line errors gracefully
|
96
|
+
* Nice
|
97
|
+
|
98
|
+
h2. Author
|
99
|
+
|
100
|
+
"Christian Hellsten":http://christianhellsten.com ("Aktagon Ltd.":http://aktagon.com)
|
101
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "mysql_backup"
|
8
|
+
gem.summary = %Q{A backup tool for MySQL.}
|
9
|
+
gem.description = %Q{A simple backup tool for MySQL that takes a backup of all MySQL databases.}
|
10
|
+
gem.email = "christian.hellsten@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/christianhellsten/mysql-backup"
|
12
|
+
gem.authors = ["Christian Hellsten"]
|
13
|
+
gem.add_dependency "sequel", ">= 0"
|
14
|
+
gem.files = FileList["[A-Z]*", "{bin,lib,test}/**/*"]
|
15
|
+
gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
|
16
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
17
|
+
end
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler (#{$!}) not available. Install it with: sudo gem install jeweler"
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'rake/testtask'
|
23
|
+
Rake::TestTask.new(:test) do |test|
|
24
|
+
test.libs << 'lib' << 'test'
|
25
|
+
test.pattern = 'test/**/test_*.rb'
|
26
|
+
test.verbose = true
|
27
|
+
end
|
28
|
+
|
29
|
+
begin
|
30
|
+
require 'rcov/rcovtask'
|
31
|
+
Rcov::RcovTask.new do |test|
|
32
|
+
test.libs << 'test'
|
33
|
+
test.pattern = 'test/**/test_*.rb'
|
34
|
+
test.verbose = true
|
35
|
+
end
|
36
|
+
rescue LoadError
|
37
|
+
task :rcov do
|
38
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
task :test => :check_dependencies
|
43
|
+
|
44
|
+
task :default => :test
|
45
|
+
|
46
|
+
require 'rake/rdoctask'
|
47
|
+
Rake::RDocTask.new do |rdoc|
|
48
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
49
|
+
|
50
|
+
rdoc.rdoc_dir = 'rdoc'
|
51
|
+
rdoc.title = "mysql_backup #{version}"
|
52
|
+
rdoc.rdoc_files.include('README*')
|
53
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
54
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/bin/mysql_backup
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
#require 'ruby-debug'
|
2
|
+
|
3
|
+
module MysqlBackup
|
4
|
+
class Backup
|
5
|
+
class << self
|
6
|
+
|
7
|
+
# TODO refactor, too long
|
8
|
+
def run
|
9
|
+
options = Options.options # TODO smells
|
10
|
+
|
11
|
+
user = options['user']
|
12
|
+
password = options['password']
|
13
|
+
host = options['host']
|
14
|
+
encoding = options['encoding']
|
15
|
+
dir = options['dir']
|
16
|
+
format = options['format']
|
17
|
+
keep = options['keep'] || 10
|
18
|
+
skip = options['skip']
|
19
|
+
mysqldump_options = options['mysqldump']['options']
|
20
|
+
path = options['mysqldump']['path']
|
21
|
+
|
22
|
+
timestamp = Time.now.strftime(format)
|
23
|
+
|
24
|
+
connection = Sequel.mysql nil, :user => user, :password => password, :host => host, :encoding => encoding
|
25
|
+
|
26
|
+
databases = []
|
27
|
+
connection['show databases'].each do |db|
|
28
|
+
databases << db[:Database]
|
29
|
+
end
|
30
|
+
databases = databases - skip #['mysql', 'test', 'information_schema']
|
31
|
+
|
32
|
+
databases.each do |db|
|
33
|
+
raise "The backup directory '#{dir}' doesn't exist" if !File.exist?(dir)
|
34
|
+
|
35
|
+
file = File.join(dir, "#{db}_#{timestamp}.sql")
|
36
|
+
p "Backing up #{db.ljust(40)} > #{file}"
|
37
|
+
|
38
|
+
cmd = "#{path}mysqldump -u#{user} -p#{password} -h#{host} #{mysqldump_options} #{db} --result-file=#{file}"
|
39
|
+
|
40
|
+
result = Pty.exec_pty(cmd, password)
|
41
|
+
|
42
|
+
# gzip
|
43
|
+
`gzip -fq #{file}`
|
44
|
+
|
45
|
+
# Find all backups and sort
|
46
|
+
# TODO improve this gem
|
47
|
+
all_backups = Dir.entries(dir).select{|f| f =~ /^#{db}/}.select{|f| File.file? File.join(dir, f) }.sort_by { |f| File.mtime(File.join(dir,f)) }.reverse
|
48
|
+
|
49
|
+
#pp all_backups
|
50
|
+
|
51
|
+
keep_backups = all_backups[0..keep] # eg. 10 latest
|
52
|
+
|
53
|
+
remove = all_backups - keep_backups
|
54
|
+
|
55
|
+
remove.each do |file|
|
56
|
+
puts "Removing backup '#{file}' keeping #{keep}"
|
57
|
+
FileUtils.rm_rf(file)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module MysqlBackup
|
4
|
+
CONF_FILE = '/etc/mysql_backup'
|
5
|
+
|
6
|
+
class Install
|
7
|
+
class << self
|
8
|
+
def ask_for_options
|
9
|
+
require "highline/import"
|
10
|
+
|
11
|
+
puts <<-PROMPT
|
12
|
+
|
13
|
+
Please enter your MySQL username and password.
|
14
|
+
|
15
|
+
PROMPT
|
16
|
+
|
17
|
+
user = ask("MySQL username : ")
|
18
|
+
password = ask("MySQL password : ") { |q| q.echo = false }
|
19
|
+
host = ask("MySQL host : ") { |q| q.default = 'localhost' }
|
20
|
+
dir = ask("Backup directory : ") { |q| q.default = '/tmp' }
|
21
|
+
|
22
|
+
[user, password, host, dir]
|
23
|
+
end
|
24
|
+
|
25
|
+
def install
|
26
|
+
begin
|
27
|
+
if File.exist?(CONF_FILE)
|
28
|
+
puts <<-WARN
|
29
|
+
|
30
|
+
#{CONF_FILE} already exists. Remove it and try again.
|
31
|
+
|
32
|
+
WARN
|
33
|
+
|
34
|
+
exit
|
35
|
+
end
|
36
|
+
|
37
|
+
user, password, host, dir = ask_for_options
|
38
|
+
|
39
|
+
File.open(CONF_FILE, 'w') do |file|
|
40
|
+
template = File.read(File.join(File.dirname(__FILE__), 'mysql_backup.yml.example'))
|
41
|
+
template.gsub!('USER', user)
|
42
|
+
template.gsub!('PASS', password)
|
43
|
+
template.gsub!('HOST', host)
|
44
|
+
template.gsub!('DIR', dir)
|
45
|
+
|
46
|
+
file << template
|
47
|
+
end
|
48
|
+
|
49
|
+
FileUtils.chmod(750, CONF_FILE)
|
50
|
+
|
51
|
+
puts <<-ERR
|
52
|
+
|
53
|
+
|
54
|
+
Configuration file #{CONF_FILE} written.
|
55
|
+
|
56
|
+
You can now backup all databases by running the following command:
|
57
|
+
|
58
|
+
$ mysql_backup
|
59
|
+
|
60
|
+
ERR
|
61
|
+
|
62
|
+
rescue Errno::EACCES => e
|
63
|
+
puts <<-ERR
|
64
|
+
|
65
|
+
You need to run this command with sudo or as root.
|
66
|
+
|
67
|
+
ERR
|
68
|
+
exit
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module MysqlBackup
|
2
|
+
class Options
|
3
|
+
class << self
|
4
|
+
def options
|
5
|
+
@@options ||= begin
|
6
|
+
begin
|
7
|
+
options = YAML::load(File.read('/etc/mysql_backup'))
|
8
|
+
rescue Errno::ENOENT
|
9
|
+
print <<-DOC
|
10
|
+
|
11
|
+
You need to create the configuration file.
|
12
|
+
|
13
|
+
To create the file, run the following commands from the command line:
|
14
|
+
|
15
|
+
$ sudo mysql_backup_install
|
16
|
+
|
17
|
+
DOC
|
18
|
+
exit
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
#
|
2
|
+
# This errors means the directory doesn't exist or there's a problem with permissions:
|
3
|
+
# /usr/local/lib/ruby/1.8/expect.rb:17:in `expect': undefined method `chr' for nil:NilClass (NoMethodError)
|
4
|
+
#
|
5
|
+
module MysqlBackup
|
6
|
+
class Pty
|
7
|
+
class << self
|
8
|
+
def exec_pty(cmd, password)
|
9
|
+
$expect_verbose = true
|
10
|
+
password = '' if password.nil?
|
11
|
+
|
12
|
+
PTY.spawn(cmd) do |reader, writer, pid|
|
13
|
+
begin
|
14
|
+
reader.expect(/Enter password/, 1) do |line|
|
15
|
+
writer.puts password
|
16
|
+
end
|
17
|
+
rescue
|
18
|
+
print reader.gets
|
19
|
+
end
|
20
|
+
|
21
|
+
begin
|
22
|
+
while line = reader.gets
|
23
|
+
# TODO detect errors we should act upon
|
24
|
+
# raise line if line.strip.length > 1
|
25
|
+
end
|
26
|
+
rescue Errno::EIO # EOF
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/mysql_backup.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#
|
2
|
+
# TODO Cleanup code
|
3
|
+
#
|
4
|
+
require 'sequel'
|
5
|
+
require 'pty'
|
6
|
+
|
7
|
+
require 'lib/mysql_backup/backup'
|
8
|
+
require 'lib/mysql_backup/options'
|
9
|
+
require 'lib/mysql_backup/pty'
|
10
|
+
require 'lib/mysql_backup/install'
|
11
|
+
|
12
|
+
module MysqlBackup
|
13
|
+
def self.version
|
14
|
+
yml = YAML.load(File.read(File.join(File.dirname(__FILE__), *%w[.. VERSION.yml])))
|
15
|
+
"#{yml[:major]}.#{yml[:minor]}.#{yml[:patch]}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.run
|
19
|
+
Backup.run
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.options
|
23
|
+
Options.options
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.install
|
27
|
+
Install.install
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
data/test/helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mysql_backup
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Christian Hellsten
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-11-01 00:00:00 +02:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: sequel
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: thoughtbot-shoulda
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
description: A simple backup tool for MySQL that takes a backup of all MySQL databases.
|
36
|
+
email: christian.hellsten@gmail.com
|
37
|
+
executables:
|
38
|
+
- mysql_backup
|
39
|
+
- mysql_backup_install
|
40
|
+
extensions: []
|
41
|
+
|
42
|
+
extra_rdoc_files:
|
43
|
+
- LICENSE
|
44
|
+
- README.rdoc
|
45
|
+
- README.textile
|
46
|
+
files:
|
47
|
+
- LICENSE
|
48
|
+
- README.rdoc
|
49
|
+
- README.textile
|
50
|
+
- Rakefile
|
51
|
+
- VERSION
|
52
|
+
- bin/mysql_backup
|
53
|
+
- bin/mysql_backup_install
|
54
|
+
- lib/mysql_backup.rb
|
55
|
+
- lib/mysql_backup/backup.rb
|
56
|
+
- lib/mysql_backup/install.rb
|
57
|
+
- lib/mysql_backup/mysql_backup.yml.example
|
58
|
+
- lib/mysql_backup/options.rb
|
59
|
+
- lib/mysql_backup/pty.rb
|
60
|
+
- test/helper.rb
|
61
|
+
- test/test_mysql_backup.rb
|
62
|
+
has_rdoc: true
|
63
|
+
homepage: http://github.com/christianhellsten/mysql-backup
|
64
|
+
licenses: []
|
65
|
+
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options:
|
68
|
+
- --charset=UTF-8
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: "0"
|
76
|
+
version:
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: "0"
|
82
|
+
version:
|
83
|
+
requirements: []
|
84
|
+
|
85
|
+
rubyforge_project:
|
86
|
+
rubygems_version: 1.3.5
|
87
|
+
signing_key:
|
88
|
+
specification_version: 3
|
89
|
+
summary: A backup tool for MySQL.
|
90
|
+
test_files:
|
91
|
+
- test/helper.rb
|
92
|
+
- test/test_mysql_backup.rb
|