]>
Commit | Line | Data |
---|---|---|
44be95f6 ER |
1 | #!/usr/bin/perl -w |
2 | use strict; | |
3 | use POSIX qw(setuid setgid); | |
4 | ||
5 | use DBI; | |
6 | use File::Temp qw(tempdir); | |
7 | use File::Path qw(rmtree); | |
8 | use delfi::mycnf; | |
9 | ||
10 | # path to ini-style config | |
11 | my $config = '/etc/bacula/backup-mysql.conf'; | |
12 | my $c = new delfi::mycnf($config); | |
13 | # force reading config file before we switch user | |
14 | $c->get(""); | |
15 | ||
16 | # how change to user mysql after we've read config | |
17 | unless ($<) { | |
18 | my $uid = getpwnam('mysql'); | |
19 | my $gid = getgrnam('mysql'); | |
20 | die "Can't find user/group mysql\n" unless $uid or $gid; | |
21 | ||
22 | $) = "$gid $gid"; | |
23 | $( = $gid; | |
24 | $> = $< = $uid; | |
25 | } | |
26 | ||
27 | # setup tmpdir | |
28 | my $backup_dir = $c->get('options', 'outdir') or die "'outdir' not defined in config\n"; | |
29 | my $tmpdir = $c->get('options', 'tmpdir') or die "'tmpdir' not defined in config\n"; | |
30 | ||
31 | if (!-d $backup_dir && !mkdir($backup_dir) && !-d $backup_dir) { | |
32 | die "backup dir '$backup_dir' not present and can't be created\n"; | |
33 | } | |
34 | if (!-d $tmpdir && !mkdir($tmpdir) && !-d $tmpdir) { | |
35 | die "tmpdir '$tmpdir' not present and can't be created\n"; | |
36 | } | |
37 | ||
38 | # process each cluster | |
39 | for my $cluster ($c->get('clusters', 'cluster')) { | |
40 | print ">>> $cluster\n"; | |
41 | backup_cluster($cluster); | |
42 | print "<<< $cluster\n"; | |
43 | } | |
44 | ||
45 | # | |
46 | # Usage: mysqlhotcopy $CLUSTER $DATABASE $USERNAME $PASSWORD $SOCKET | |
47 | # | |
48 | sub mysqlhotcopy { | |
49 | my ($cluster, $database, $user, $password, $socket) = @_; | |
50 | ||
51 | my $dstdir = tempdir("bbm.XXXXXX", DIR => $tmpdir); | |
52 | ||
53 | # make backup with mysqlhotcopy | |
54 | my @shell = ('mysqlhotcopy'); | |
55 | push(@shell, '-u', $user) if $user; | |
56 | push(@shell, '-p', $password) if $password; | |
57 | push(@shell, '-S', $socket) if $socket; | |
58 | push(@shell, $database, $dstdir); | |
59 | system(@shell) == 0 or die "mysqlhotcopy failed: $?\n"; | |
60 | ||
61 | # put it to "production dir" | |
62 | my $cluster_dir = "$backup_dir/$cluster"; | |
63 | if (!-d $cluster_dir && !mkdir($cluster_dir) && !-d $cluster_dir) { | |
64 | die "cluster dir '$cluster_dir' not present and can't be created\n"; | |
65 | } | |
66 | ||
67 | my $dirname = "$backup_dir/$cluster/$database"; | |
68 | if (-d $dirname) { | |
69 | rmtree($dirname); | |
70 | } | |
71 | ||
72 | my $srcdir= "$dstdir/$database"; | |
73 | rename($srcdir, $dirname) or die "Rename '$srcdir'->'$dirname' failed: $!\n"; | |
74 | ||
75 | rmdir($dstdir) or warn $!; | |
76 | } | |
77 | ||
78 | sub backup_cluster { | |
79 | my ($cluster) = @_; | |
80 | ||
81 | # get db connection info | |
82 | my $user = $c->get($cluster, 'user') || $c->get('client', 'user'); | |
83 | my $password = $c->get($cluster, 'password') || $c->get('client', 'password'); | |
84 | my $socket = $c->get($cluster, 'socket') || $c->get('client', 'socket'); | |
85 | ||
86 | # get databases to backup | |
87 | my @dbs; | |
88 | ||
89 | my @include = $c->get($cluster, 'include_databases'); | |
90 | my @exclude = $c->get($cluster, 'exclude_databases'); | |
91 | if (@exclude or !@include) { | |
92 | my $dbh = new DB($user, $password, $socket); | |
93 | my $sth = $dbh->prepare("show databases"); | |
94 | $sth->execute(); | |
95 | while (my($dbname) = $sth->fetchrow_array) { | |
96 | next if lc($dbname) eq 'information_schema'; | |
97 | push @dbs, $dbname unless grep { m{^\Q$dbname\E$} } @exclude; | |
98 | } | |
99 | undef $dbh; | |
100 | } | |
101 | ||
102 | # now do the backup | |
103 | foreach my $db (@dbs) { | |
104 | mysqlhotcopy($cluster, $db, $user, $password, $socket); | |
105 | } | |
106 | } | |
107 | ||
108 | package DB; | |
109 | ||
110 | # DB class for simple Database connection | |
111 | sub new { | |
112 | my $self = shift; | |
113 | my $class = ref($self) || $self; | |
114 | ||
115 | my ($user, $password, $socket) = @_; | |
116 | my $dsn = ''; | |
117 | $dsn .= "mysql_socket=$socket" if $socket; | |
118 | my $dbh = DBI->connect("DBI:mysql:$dsn", $user, $password, { PrintError => 0, RaiseError => 1 }); | |
119 | return $dbh; | |
120 | } |