]> git.pld-linux.org Git - packages/bacula-backup-mysql.git/blobdiff - bacula-backup-mysql
- v0.3: cleanup tmp dir when backup failed
[packages/bacula-backup-mysql.git] / bacula-backup-mysql
index e41b5f8fd9fb63da0dff96c5599661306f5d7dd5..a7e48f240cf88ad8873c76515ae658516dd665c0 100644 (file)
@@ -1,24 +1,45 @@
-#!/usr/bin/perl -w
+#!/usr/bin/perl -ws
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to:
+#
+#  Free Software Foundation, Inc.
+#  59 Temple Place - Suite 330
+#  Boston, MA 02111-1307, USA.
+
+# Rudimentary switch parsing. Must be in main package.
+our $cleanup;
+
+package BBM;
 use strict;
 use POSIX qw(setuid setgid);
-
 use DBI;
 use File::Temp qw(tempdir);
 use File::Path qw(rmtree);
-use delfi::mycnf;
 
-# path to ini-style config
+
+# path to Apache HTTPd-style config
 my $config = '/etc/bacula/backup-mysql.conf';
-my $c = new delfi::mycnf($config);
-# force reading config file before we switch user
-$c->get("");
+my $c = new BBM::Config($config);
 
-# how change to user mysql after we've read config
+# now change to user mysql after we've read config
 unless ($<) {
        my $uid = getpwnam('mysql');
        my $gid = getgrnam('mysql');
        die "Can't find user/group mysql\n" unless $uid or $gid;
 
+       # CWD could not be accessible for mysql user
+       chdir("/");
+
        $) = "$gid $gid";
        $( = $gid;
        $> = $< = $uid;
@@ -38,16 +59,22 @@ if (!-d $tmpdir && !mkdir($tmpdir) && !-d $tmpdir) {
 # process each cluster
 for my $cluster ($c->get('clusters', 'cluster')) {
        print ">>> $cluster\n";
-       backup_cluster($cluster);
+       if ($cleanup) {
+               cleanup_cluster($cluster);
+       } else {
+               backup_cluster($cluster);
+       }
        print "<<< $cluster\n";
 }
 
-# 
+#
 # Usage: mysqlhotcopy $CLUSTER $DATABASE $USERNAME $PASSWORD $SOCKET
 #
 sub mysqlhotcopy {
        my ($cluster, $database, $user, $password, $socket) = @_;
 
+       print ">>>> mysqlhotcopy $database\n";
+
        my $dstdir = tempdir("bbm.XXXXXX", DIR => $tmpdir);
 
        # make backup with mysqlhotcopy
@@ -61,6 +88,7 @@ sub mysqlhotcopy {
        # put it to "production dir"
        my $cluster_dir = "$backup_dir/$cluster";
        if (!-d $cluster_dir && !mkdir($cluster_dir) && !-d $cluster_dir) {
+               rmtree($dstdir);
                die "cluster dir '$cluster_dir' not present and can't be created\n";
        }
 
@@ -69,10 +97,23 @@ sub mysqlhotcopy {
                rmtree($dirname);
        }
 
-       my $srcdir= "$dstdir/$database";
-       rename($srcdir, $dirname) or die "Rename '$srcdir'->'$dirname' failed: $!\n";
+       my $srcdir = "$dstdir/$database";
+       unless (rename($srcdir, $dirname)) {
+               rmtree($dstdir);
+               die "Rename '$srcdir'->'$dirname' failed: $!\n";
+       }
 
        rmdir($dstdir) or warn $!;
+
+       print "<<<< mysqlhotcopy $database\n";
+}
+
+sub cleanup_cluster {
+       my ($cluster) = @_;
+       my $cluster_dir = "$backup_dir/$cluster";
+       print ">>>> cleanup $cluster_dir\n";
+       rmtree($cluster_dir);
+       print "<<<< cleanup $cluster_dir\n";
 }
 
 sub backup_cluster {
@@ -84,28 +125,34 @@ sub backup_cluster {
        my $socket = $c->get($cluster, 'socket') || $c->get('client', 'socket');
 
        # get databases to backup
-       my @dbs;
+       my @include = $c->get($cluster, 'include_database');
+       my @exclude = $c->get($cluster, 'exclude_database');
+
+       # start with include list
+       my %dbs = map { $_ => 1 } @include;
 
-       my @include = $c->get($cluster, 'include_databases');
-       my @exclude = $c->get($cluster, 'exclude_databases');
        if (@exclude or !@include) {
-               my $dbh = new DB($user, $password, $socket);
+               my $dbh = new BBM::DB($user, $password, $socket);
                my $sth = $dbh->prepare("show databases");
                $sth->execute();
                while (my($dbname) = $sth->fetchrow_array) {
                        next if lc($dbname) eq 'information_schema';
-                       push @dbs, $dbname unless grep { m{^\Q$dbname\E$} } @exclude;
+                       $dbs{$dbname} = 1;
                }
                undef $dbh;
        }
 
+       # remove excluded databases
+       delete @dbs{@exclude};
+
        # now do the backup
-       foreach my $db (@dbs) {
+       foreach my $db (keys %dbs) {
                mysqlhotcopy($cluster, $db, $user, $password, $socket);
        }
 }
 
-package DB;
+package BBM::DB;
+use strict;
 
 # DB class for simple Database connection
 sub new {
@@ -118,3 +165,68 @@ sub new {
        my $dbh = DBI->connect("DBI:mysql:$dsn", $user, $password, { PrintError => 0, RaiseError => 1 });
        return $dbh;
 }
+
+package BBM::Config;
+use strict;
+use Config::General;
+
+sub new {
+       my $self = shift;
+       my $class = ref($self) || $self;
+       my $file = shift;
+
+       my $config = new Config::General(-ConfigFile => $file, -LowerCaseNames => 1);
+       my $this = { $config->getall() };
+       bless($this, $class);
+}
+
+sub get {
+       my ($self, $section, $key) = @_;
+       my $h = $self;
+
+       # descend to [cluster] if $section not present in root tree
+       unless (exists $h->{$section}) {
+               $h = $h->{cluster};
+       }
+
+       # pay attention if callee wanted arrays
+       return wantarray ? () : undef unless exists $h->{$section};
+       return wantarray ? () : undef unless exists $h->{$section}->{$key};
+
+       # deref if wanted array and is arrayref
+       return @{$h->{$section}->{$key}} if wantarray && ref $h->{$section}->{$key} eq 'ARRAY';
+
+       return $h->{$section}->{$key};
+}
+
+
+__END__
+
+=head1 NAME
+
+bacula-backup-mysql - A hook for Bacula to backup mysql databases using mysqlhotcopy.
+
+=head1 SYNOPSIS
+
+  Job {
+    Name = "example.org-mysql"
+    ...
+    # This prepares the backup
+    Client Run Before Job = "/usr/sbin/bacula-backup-mysql"
+    # This deletes the copy of the catalog
+    Client Run After Job = "/usr/sbin/bacula-backup-mysql -cleanup"
+  }
+
+=head1 DESCRIPTION
+
+This is a script to be setup as C<Client Run Before Job> in Bacula.
+
+=head1 AUTHOR
+
+Copyright (C) 2009-2010, Elan RuusamE<auml>e <glen@delfi.ee>
+
+=head1 SEE ALSO
+
+http://www.bacula.org/
+
+=cut
This page took 0.327862 seconds and 4 git commands to generate.