]> git.pld-linux.org Git - packages/bacula-backup-mysql.git/blame - bacula-backup-mysql
- v0.5: remove target dir before making backup to tmp dir, avoiding double disk usage
[packages/bacula-backup-mysql.git] / bacula-backup-mysql
CommitLineData
1d217da6 1#!/usr/bin/perl -ws
46478424
ER
2# This program is free software; you can redistribute it and/or modify
3# it under the terms of the GNU General Public License as published by
4# the Free Software Foundation; either version 2 of the License, or
5# (at your option) any later version.
6#
7# This program is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
36d65868 9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46478424
ER
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program; if not, write to:
14#
15# Free Software Foundation, Inc.
16# 59 Temple Place - Suite 330
17# Boston, MA 02111-1307, USA.
18
1d217da6
ER
19# Rudimentary switch parsing. Must be in main package.
20our $cleanup;
21
38d6af1e 22package BBM;
44be95f6
ER
23use strict;
24use POSIX qw(setuid setgid);
44be95f6
ER
25use DBI;
26use File::Temp qw(tempdir);
27use File::Path qw(rmtree);
44be95f6 28
947fde71
ER
29# path to Apache HTTPd-style config
30my $config = '/etc/bacula/backup-mysql.conf';
38d6af1e 31my $c = new BBM::Config($config);
44be95f6 32
7b895eeb 33# now change to user mysql after we've read config
44be95f6
ER
34unless ($<) {
35 my $uid = getpwnam('mysql');
36 my $gid = getgrnam('mysql');
37 die "Can't find user/group mysql\n" unless $uid or $gid;
38
1d217da6
ER
39 # CWD could not be accessible for mysql user
40 chdir("/");
41
44be95f6 42 $) = "$gid $gid";
36d65868
ER
43 $( = $gid;
44 $> = $< = $uid;
44be95f6
ER
45}
46
47# setup tmpdir
48my $backup_dir = $c->get('options', 'outdir') or die "'outdir' not defined in config\n";
36d65868 49my $tmpdir = $c->get('options', 'tmpdir') or die "'tmpdir' not defined in config\n";
44be95f6
ER
50
51if (!-d $backup_dir && !mkdir($backup_dir) && !-d $backup_dir) {
52 die "backup dir '$backup_dir' not present and can't be created\n";
53}
54if (!-d $tmpdir && !mkdir($tmpdir) && !-d $tmpdir) {
55 die "tmpdir '$tmpdir' not present and can't be created\n";
56}
57
58# process each cluster
59for my $cluster ($c->get('clusters', 'cluster')) {
21563d32 60 print ">>> cluster: $cluster\n";
1d217da6
ER
61 if ($cleanup) {
62 cleanup_cluster($cluster);
63 } else {
64 backup_cluster($cluster);
65 }
21563d32 66 print "<<< end cluster: $cluster\n";
44be95f6
ER
67}
68
46478424 69#
44be95f6
ER
70# Usage: mysqlhotcopy $CLUSTER $DATABASE $USERNAME $PASSWORD $SOCKET
71#
72sub mysqlhotcopy {
36d65868
ER
73 my ($cluster, $db, $user, $password, $socket) = @_;
74
75 # strip $database to contain only db name, as the rest of the code assumes $database is just database name
76 # i.e: include_database teensForum5./~(phorum_forums|phorum_users)/
77 my ($database) = $db =~ /^([^\.]+)/;
44be95f6
ER
78
79 my $dstdir = tempdir("bbm.XXXXXX", DIR => $tmpdir);
80
21563d32
ER
81 # remove output dir before backup,
82 # otherwise the disk space requirement would double
83 my $dirname = "$backup_dir/$cluster/$database";
84 if (-d $dirname) {
85 print ">>>> rmtree $dirname\n";
86 rmtree($dirname);
87 }
88
44be95f6
ER
89 # make backup with mysqlhotcopy
90 my @shell = ('mysqlhotcopy');
91 push(@shell, '-u', $user) if $user;
92 push(@shell, '-p', $password) if $password;
93 push(@shell, '-S', $socket) if $socket;
36d65868 94 push(@shell, $db, $dstdir);
21563d32 95 print ">>>> mysqlhotcopy $database\n";
44be95f6
ER
96 system(@shell) == 0 or die "mysqlhotcopy failed: $?\n";
97
98 # put it to "production dir"
99 my $cluster_dir = "$backup_dir/$cluster";
100 if (!-d $cluster_dir && !mkdir($cluster_dir) && !-d $cluster_dir) {
49da4557 101 rmtree($dstdir);
44be95f6
ER
102 die "cluster dir '$cluster_dir' not present and can't be created\n";
103 }
104
49da4557
ER
105 my $srcdir = "$dstdir/$database";
106 unless (rename($srcdir, $dirname)) {
9a263aad 107 my $err = $!;
49da4557 108 rmtree($dstdir);
9a263aad 109 die "Rename '$srcdir'->'$dirname' failed: $err\n";
49da4557 110 }
44be95f6
ER
111
112 rmdir($dstdir) or warn $!;
62f7c875
ER
113
114 print "<<<< mysqlhotcopy $database\n";
44be95f6
ER
115}
116
1d217da6
ER
117sub cleanup_cluster {
118 my ($cluster) = @_;
119 my $cluster_dir = "$backup_dir/$cluster";
120 print ">>>> cleanup $cluster_dir\n";
121 rmtree($cluster_dir);
122 print "<<<< cleanup $cluster_dir\n";
123}
124
44be95f6
ER
125sub backup_cluster {
126 my ($cluster) = @_;
127
128 # get db connection info
129 my $user = $c->get($cluster, 'user') || $c->get('client', 'user');
130 my $password = $c->get($cluster, 'password') || $c->get('client', 'password');
131 my $socket = $c->get($cluster, 'socket') || $c->get('client', 'socket');
132
133 # get databases to backup
38d6af1e
ER
134 my @include = $c->get($cluster, 'include_database');
135 my @exclude = $c->get($cluster, 'exclude_database');
44be95f6 136
38d6af1e
ER
137 # start with include list
138 my %dbs = map { $_ => 1 } @include;
62f7c875 139
44be95f6 140 if (@exclude or !@include) {
38d6af1e 141 my $dbh = new BBM::DB($user, $password, $socket);
44be95f6
ER
142 my $sth = $dbh->prepare("show databases");
143 $sth->execute();
144 while (my($dbname) = $sth->fetchrow_array) {
145 next if lc($dbname) eq 'information_schema';
949a3e79 146 next if lc($dbname) eq 'performance_schema';
38d6af1e 147 $dbs{$dbname} = 1;
44be95f6
ER
148 }
149 undef $dbh;
150 }
151
38d6af1e
ER
152 # remove excluded databases
153 delete @dbs{@exclude};
154
44be95f6 155 # now do the backup
38d6af1e 156 foreach my $db (keys %dbs) {
44be95f6
ER
157 mysqlhotcopy($cluster, $db, $user, $password, $socket);
158 }
159}
160
38d6af1e
ER
161package BBM::DB;
162use strict;
44be95f6
ER
163
164# DB class for simple Database connection
165sub new {
72cc922f 166 my $self = shift;
44be95f6
ER
167 my ($user, $password, $socket) = @_;
168 my $dsn = '';
169 $dsn .= "mysql_socket=$socket" if $socket;
170 my $dbh = DBI->connect("DBI:mysql:$dsn", $user, $password, { PrintError => 0, RaiseError => 1 });
171 return $dbh;
172}
38d6af1e
ER
173
174package BBM::Config;
175use strict;
176use Config::General;
177
178sub new {
179 my $self = shift;
180 my $class = ref($self) || $self;
181 my $file = shift;
182
183 my $config = new Config::General(-ConfigFile => $file, -LowerCaseNames => 1);
184 my $this = { $config->getall() };
185 bless($this, $class);
186}
187
188sub get {
189 my ($self, $section, $key) = @_;
190 my $h = $self;
191
192 # descend to [cluster] if $section not present in root tree
193 unless (exists $h->{$section}) {
194 $h = $h->{cluster};
195 }
196
197 # pay attention if callee wanted arrays
198 return wantarray ? () : undef unless exists $h->{$section};
199 return wantarray ? () : undef unless exists $h->{$section}->{$key};
62f7c875
ER
200
201 # deref if wanted array and is arrayref
202 return @{$h->{$section}->{$key}} if wantarray && ref $h->{$section}->{$key} eq 'ARRAY';
203
38d6af1e
ER
204 return $h->{$section}->{$key};
205}
46478424
ER
206
207
208__END__
209
210=head1 NAME
211
212bacula-backup-mysql - A hook for Bacula to backup mysql databases using mysqlhotcopy.
213
214=head1 SYNOPSIS
215
216 Job {
217 Name = "example.org-mysql"
218 ...
72b32af8 219 # This prepares the backup
46478424
ER
220 Client Run Before Job = "/usr/sbin/bacula-backup-mysql"
221 # This deletes the copy of the catalog
222 Client Run After Job = "/usr/sbin/bacula-backup-mysql -cleanup"
223 }
224
225=head1 DESCRIPTION
226
227This is a script to be setup as C<Client Run Before Job> in Bacula.
228
0183092d
ER
229=head1 CONFIGURATION
230
231Config starts with C<E<lt>clustersE<gt>> block, which you can define several
232database instances to be backed up.
233
234Each C<cluster> should define connection dsn and tables to be backed up.
235
236To define connection dsn, you can also define common options in
237C<E<lt>clientE<gt>> section, those options would be shared for each cluster
238which has not overriden the specific option.
239
240In C<E<lt>clusterE<gt>> sections, you should list databases to be backed up.
241You can use C<include_database> option to implicitly list which databases to be
242backed up. If you omit C<include_database> option, all databases are backed up
36d65868 243which can be seen with C<show tables> query. To exclude databases from that
0183092d
ER
244list you can use C<exclude_database> options.
245
36d65868
ER
246Additionally C<include_database> supports table regexp, which is passed
247directly to mysqlhotcopy(1). This allows you to include or exclude tables from
248each database backup.
249
0183092d
ER
250=head1 EXAMPLE CONFIGURATION
251
252 # clusters to backup
253 # there is nothing special about name "mysql", name just picked as convience
254 <clusters>
255 cluster mysql
36d65868
ER
256 cluster eventum
257 cluster forums
0183092d
ER
258 </clusters>
259
260 # client connection parameters, can be overriden per cluster
261 <client>
262 user mysql
263 password secret
264 </client>
265
266 # global options, can be overriden per cluster
267 <options>
268 tmpdir /srv/bacula/tmp
269 outdir /srv/bacula/mysql
270 </options>
271
272 # mysql cluster: backup all but mysql database
273 <cluster mysql>
274 socket /var/lib/mysql/mysql.sock
275 exclude_database mysql
276 </cluster>
277
36d65868
ER
278 # forums cluster: exclude phorum_forums and phorum_users tables
279 <cluster forums>
280 user mysql
281 socket /var/lib/mysql/mysql.sock
282
283 # include_database can also support table regexp for mysqlhotcopy:
284 include_database teensForum5./~(phorum_forums|phorum_users)/
285 </cluster>
286
46478424
ER
287=head1 AUTHOR
288
0183092d 289Copyright (C) 2009-2012, Elan RuusamE<auml>e <glen@delfi.ee>
46478424
ER
290
291=head1 SEE ALSO
292
293http://www.bacula.org/
294
295=cut
This page took 0.09998 seconds and 4 git commands to generate.