jage-rmysqldump 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/rmysqldump.rb +198 -0
- data/rmysqldump.conf +23 -0
- metadata +63 -0
data/bin/rmysqldump.rb
ADDED
@@ -0,0 +1,198 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# $Id: rmysqldump.rb,v 1.7 2007/11/28 11:48:22 jage Exp $
|
4
|
+
#
|
5
|
+
# Written by Johan Eckerstr�m <johan@jage.se>
|
6
|
+
#
|
7
|
+
# 2007-05-22 - Stop using regexp for owner_map \
|
8
|
+
# and improve syslog message
|
9
|
+
# 2006-12-19 - Compression for servers
|
10
|
+
# 2006-12-01 - External configuration file
|
11
|
+
# 2006-11-21 - Easier to change the user mapping regexp
|
12
|
+
# 2006-10-31 - Added syslog capabilities
|
13
|
+
# 2006-08-06 - First version
|
14
|
+
#
|
15
|
+
# Todo:
|
16
|
+
# - Add regexp capabilities for the database-specifications
|
17
|
+
# - Record elapsed time for backup
|
18
|
+
|
19
|
+
begin
|
20
|
+
require 'fileutils'
|
21
|
+
require 'syslog'
|
22
|
+
require 'rubygems'
|
23
|
+
require 'mysql'
|
24
|
+
rescue LoadError
|
25
|
+
$stderr.puts 'Could not load required libraries'; exit 1
|
26
|
+
end
|
27
|
+
|
28
|
+
begin
|
29
|
+
load '/etc/rmysqldump.conf'
|
30
|
+
rescue LoadError
|
31
|
+
$stderr.puts 'Could not load configuration'; exit 1
|
32
|
+
end
|
33
|
+
|
34
|
+
$users = []
|
35
|
+
IO.foreach('/etc/passwd') do |line|
|
36
|
+
$users << /(^[\w]+)/.match(line).to_s.strip
|
37
|
+
end
|
38
|
+
|
39
|
+
module MySQL
|
40
|
+
class Databases
|
41
|
+
|
42
|
+
attr_reader :list
|
43
|
+
|
44
|
+
def initialize
|
45
|
+
@list = databases.collect {|i| Database.new(i) }
|
46
|
+
end
|
47
|
+
|
48
|
+
def failed
|
49
|
+
@list.select {|i| i.fail }
|
50
|
+
end
|
51
|
+
|
52
|
+
def skipped
|
53
|
+
@list.select {|i| i.skip }
|
54
|
+
end
|
55
|
+
|
56
|
+
def successes
|
57
|
+
@list.select {|i| i.success }
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def databases
|
63
|
+
list = []
|
64
|
+
connection = Mysql.real_connect($server[:host],
|
65
|
+
$server[:user],
|
66
|
+
$server[:password])
|
67
|
+
result = connection.query('SHOW DATABASES')
|
68
|
+
result.each {|db| list << db.to_s }
|
69
|
+
result.free
|
70
|
+
list
|
71
|
+
rescue Mysql::Error => error
|
72
|
+
$stderr.puts error.message; exit 1
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class Database
|
77
|
+
|
78
|
+
attr_reader :name, :lock, :owner, :group, :charset, :skip
|
79
|
+
attr_accessor :success
|
80
|
+
|
81
|
+
def initialize(name)
|
82
|
+
@options = $database_options[name.to_sym] ||= Hash.new
|
83
|
+
|
84
|
+
@name = name
|
85
|
+
@lock = option_for(:lock)
|
86
|
+
@owner = option_for(:owner).to_s
|
87
|
+
@group = option_for(:group).to_s
|
88
|
+
@charset = option_for(:charset).to_s
|
89
|
+
@skip = option_for(:skip)
|
90
|
+
|
91
|
+
# Would be better if the database specific owner could override this
|
92
|
+
if option_for(:map_owner) && owner = find_owner
|
93
|
+
@owner = owner
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def to_s
|
98
|
+
name
|
99
|
+
end
|
100
|
+
|
101
|
+
def path
|
102
|
+
"#{$archive_dir}/#{self}.sql.gz"
|
103
|
+
end
|
104
|
+
|
105
|
+
def fail
|
106
|
+
!success && !skip
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
def option_for(key)
|
112
|
+
@options[key] || $global_options[key] || false
|
113
|
+
end
|
114
|
+
|
115
|
+
def find_owner
|
116
|
+
match = $users.select do |u|
|
117
|
+
@name.include?(u) && u == @name[0...u.length]
|
118
|
+
end
|
119
|
+
|
120
|
+
if match.empty?
|
121
|
+
false
|
122
|
+
else
|
123
|
+
match.to_s
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
class Dump
|
129
|
+
def initialize(databases)
|
130
|
+
@databases = databases
|
131
|
+
|
132
|
+
unless mysqldump_working?
|
133
|
+
failure("Could not execute #{$mysqldump}"); exit 1
|
134
|
+
end
|
135
|
+
|
136
|
+
unless File.directory?($archive_dir)
|
137
|
+
failure("Could not save in #{$archive_dir}"); exit 1
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def execute
|
142
|
+
Syslog.open(ident='rmysqldump', facility=Syslog::LOG_DAEMON)
|
143
|
+
@databases.list.each do |database|
|
144
|
+
unless database.skip
|
145
|
+
`#{$mysqldump} #{parameters_for(database)} #{database} | #{$gzip} > #{database.path}`
|
146
|
+
failure("Could not dump #{database}") unless $?.success?
|
147
|
+
begin
|
148
|
+
FileUtils.chown database.owner, database.group, database.path
|
149
|
+
FileUtils.chmod 0660, database.path
|
150
|
+
database.success = true if $?.success?
|
151
|
+
rescue => error
|
152
|
+
failure("Could not set permissions: #{error.message}")
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
message = "#{@databases.successes.length} databases dumped successfully"
|
157
|
+
if @databases.skipped.length > 0
|
158
|
+
message += ", #{@databases.skipped.length} skipped"
|
159
|
+
end
|
160
|
+
Syslog.info(message)
|
161
|
+
|
162
|
+
# Inform about failures
|
163
|
+
if @databases.failed.length > 0
|
164
|
+
error_message = 'Failed databases:'
|
165
|
+
@databases.failed.each do |db|
|
166
|
+
error_message << " #{db},"
|
167
|
+
end
|
168
|
+
error_message.gsub!(/,$/, '.')
|
169
|
+
Syslog.err(error_message)
|
170
|
+
end
|
171
|
+
|
172
|
+
Syslog.close
|
173
|
+
end
|
174
|
+
|
175
|
+
private
|
176
|
+
|
177
|
+
def failure(message)
|
178
|
+
$stderr.puts message
|
179
|
+
Syslog.err(message) if Syslog.opened?
|
180
|
+
end
|
181
|
+
|
182
|
+
def mysqldump_working?
|
183
|
+
File.readable?($mysqldump) and File.executable?($mysqldump)
|
184
|
+
end
|
185
|
+
|
186
|
+
def parameters_for(database)
|
187
|
+
params = "--default-character-set=#{database.charset} \
|
188
|
+
--user #{$server[:user]} \
|
189
|
+
--password=#{$server[:password]} \
|
190
|
+
--host #{$server[:host]}"
|
191
|
+
params += " --compress" if $server[:compress]
|
192
|
+
params += " --lock-tables" if database.lock
|
193
|
+
params
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
MySQL::Dump.new(MySQL::Databases.new).execute
|
data/rmysqldump.conf
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
$mysqldump = '/usr/local/bin/mysqldump'
|
2
|
+
$gzip = '/usr/bin/gzip'
|
3
|
+
$archive_dir = '/archive/mysqldump'
|
4
|
+
|
5
|
+
$server = {
|
6
|
+
:host => 'localhost',
|
7
|
+
:user => 'dumper',
|
8
|
+
:password => 'hemlis',
|
9
|
+
:compress => true # Compress the data stream
|
10
|
+
}
|
11
|
+
|
12
|
+
$database_options = {
|
13
|
+
:apachelogs => { :skip => true }
|
14
|
+
}
|
15
|
+
|
16
|
+
$global_options = {
|
17
|
+
:lock => false, # Lock the tables before dump
|
18
|
+
:owner => 'root', # Default user to own the backups
|
19
|
+
:group => 'wheel', # Default group to own the backups
|
20
|
+
:charset => 'latin1', # The charset to set in mysqldump
|
21
|
+
:map_owner => true # Match database name, if name starts
|
22
|
+
# a users name, he's the owner
|
23
|
+
}
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jage-rmysqldump
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- "Johan Eckerstr\xC3\xB6m"
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-01-08 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: mysql
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
description: Used for dumping mysql databases on shared servers
|
26
|
+
email: johan@duh.se
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files: []
|
32
|
+
|
33
|
+
files:
|
34
|
+
- rmysqldump.conf
|
35
|
+
- bin/rmysqldump.rb
|
36
|
+
has_rdoc: false
|
37
|
+
homepage: http://github.com/jage/rmysqldump
|
38
|
+
post_install_message:
|
39
|
+
rdoc_options: []
|
40
|
+
|
41
|
+
require_paths:
|
42
|
+
- lib
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: "0"
|
48
|
+
version:
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0"
|
54
|
+
version:
|
55
|
+
requirements: []
|
56
|
+
|
57
|
+
rubyforge_project:
|
58
|
+
rubygems_version: 1.2.0
|
59
|
+
signing_key:
|
60
|
+
specification_version: 2
|
61
|
+
summary: Dump MySQL databases
|
62
|
+
test_files: []
|
63
|
+
|