root/zetaback_agent.in

Revision ae9700b895f444ba92c6aac759ec8a6d257ae0e3, 9.2 kB (checked in by Mark Harrison <mark@omniti.com>, 3 years ago)

Add option to exclude alternate/inactive boot environments from a backup

This option obtains the ID of the currently active boot environment, and then
looks for filesystems eith either the BE uuid or parent BE uuid (for zone
filesystems) zfs properties set. If they are set, but don't match the uuid of
the current boot environment, they are excluded. This option is configurable
in zetaback_agent.conf.

  • Property mode set to 100755
Line 
1 #!/usr/bin/perl
2
3 # Copyright (c) 2007 OmniTI Computer Consulting, Inc. All rights reserved.
4 # For information on licensing see:
5 #   https://labs.omniti.com/zetaback/trunk/LICENSE
6
7 use strict;
8 use Getopt::Long;
9 use POSIX qw/mkfifo/;
10 use Data::Dumper;
11
12 use vars qw/%conf $version_string
13             $PREFIX $CONF $LIST $FULL $SNAP $ZFS $BASE $RESTORE $VERSION
14             $BUG_6343779 $NEEDSFD $DSET/;
15 $version_string = '1.0.6';
16 $PREFIX = q^__PREFIX__^;
17 $CONF = qq^$PREFIX/etc/zetaback_agent.conf^;
18 $NEEDSFD = ($^O eq 'darwin') ? 1 : 0;
19
20 =pod
21
22 =head1 NAME
23
24 zetaback_agent - client-side component of zetaback.
25
26 =head1 SYNOPSIS
27
28   zetaback_agent -v
29
30   zetaback_agent -l [-c conf]
31
32   zetaback_agent -r [-b <timestamp>] [-c conf] [-z zfs]
33
34   zetaback -f <timestamp> [-c conf] [-z zfs]
35
36   zetaback -i <timestamp> [-c conf] [-z zfs]
37
38   zetaback -d <snap> -z <zfs> [-c conf]
39
40 =cut
41
42 GetOptions(
43   "c=s" => \$CONF,
44   "l"   => \$LIST,
45   "r"   => \$RESTORE,
46   "z=s" => \$ZFS,
47   "d=s" => \$SNAP,
48   "f=s" => \$FULL,
49   "i=s" => \$BASE,
50   "s=s" => \$DSET,
51   "b=s" => \$BUG_6343779,
52   "v"   => \$VERSION,
53 );
54
55 =pod
56
57 =head1 DESCRIPTION
58
59 B<zetaback_agent> handles requests from zetaback and performs the requested
60 operations on a host.  Normally B<zetaback_agent> is only called by
61 zetaback and should never need to be invoked directly.
62
63 =head1 OPTIONS
64
65 The following options are available:
66
67 =over
68
69 =item -c <conf>
70
71 Use the specified file as the configuration file.  The default file, if
72 none is specified is /usr/local/etc/zetaback_agent.conf.  The prefix of this
73 file may also be specified as an argument to the configure script.
74
75 =item -d <snap>
76
77 Delete the specified snapshot.  Requires the use of -z to specify the
78 ZFS filesystem.
79
80 =item -f <timestamp>
81
82 Perform a full backup.  The name of the backup will include <timestamp>,
83 which is provided by the backup server.
84
85 =item -i <timestamp>
86
87 Perform an incremental backup.  The name of the backup will include
88 <timestamp>, which is provided by the backup server.
89
90 =item -s <timestamp>
91
92 Perform a dataset backup.  The name of the backup will include
93 <timestamp>, which is provided by the backup server. This requires the -i
94 option to specify the base dataset the expected by the backup server.
95
96 =item -l
97
98 List ZFS filesystems.
99
100 =item -r
101
102 Perform a restore.
103
104 =item -b
105
106 When performing a restore, if -b is specified, it informs the agent that
107 the receive command is an incremental based of the full snapshot with the
108 timestamp specified.  The agent will unmount and rollback the filesystem
109 prior to applying the incremental in order to work around bug 6343779.
110
111 =item -v
112
113 Print the version number and exit.
114
115 =item -z
116
117 Specify a ZFS filesystem to backup, restore, or delete.
118
119 =back
120
121 =cut
122
123 if($VERSION) {
124   print "zetaback_agent: $version_string\n";
125   exit 0;
126 }
127
128 =pod
129
130 =head1 CONFIGURATION
131
132 The zetaback_agent configuration file contains a pattern list of ZFS
133 filesystems to be backed up.  The pattern list is a Perl-compatible
134 regular expression (PCRE).  Only one 'pattern=' line is permitted.
135
136 The pattern acts as a filter to reduce the list of filesystems to
137 be backed up.  Further excludes from this list are possible by setting
138 a user property on any filesystem that should not be backed up, even
139 if it matches the pattern:
140
141   zfs set com.omniti.labs.zetaback:exclude=on pool/fs
142
143 User properties are available on Solaris 10 8/07 and newer, and on
144 Solaris Express build 48 and newer.
145
146 Once a pattern and/or exclude properties have been configured on a host,
147 the list of remaining filesystems can be validated by invoking
148 zetaback_agent with the -l option.
149
150 =head2 Excluding inactive boot environments
151
152 The zetaback_agent configuration file also has an option to not back up filesystems that are part of an alternate/inactive boot environment. To enable this option, add the following to the configuration file:
153
154   exclude_inactive_be=1
155
156 =head1 CONFIGURATION EXAMPLES
157
158 =head2 All ZFS filesystems
159
160 This pattern matches all ZFS filesystems.
161
162   pattern=.
163
164 =head2 Substring match
165
166 This will match anywhere in the name of the ZFS filesystem.  This is
167 helpful for catching all ZFS filesystems in a particular zpool, while
168 excluding any others.
169
170   pattern=zones
171
172 =head2 Left-anchored names
173
174 This pattern matches all ZFS filesystems whose names begin with 'www'.
175
176   pattern=^www
177
178 =head2 Specific ZFS filesystems
179
180 This pattern matches specific ZFS filesystems.
181
182   pattern=(?:data|mirrors|www)
183
184 =head2 Combining with property-based exclude
185
186 All filesystems in pool 'zones' except 'foo'
187
188   pattern=^zones
189
190   (At a root shell or with pfexec/sudo):
191   zfs set com.omniti.labs.zetaback:exclude=on zones/foo
192
193 =cut
194
195 # Read our config in
196 $conf{pattern} = '.';
197 $conf{exclude_inactive_be} = '0';
198 open(CONF, "<$CONF");
199 while(<CONF>) { /^\s*([^#](?:\S*)?)\s*=\s*(\S+)/ && ($conf{lc($1)} = $2); }
200 close(CONF);
201
202 sub zfs_agent_remove_snap {
203   my $target = $ZFS . '@';
204   die "zfs_agent_remove_snap: insufficient args\n" unless($ZFS && $SNAP);
205   if($SNAP eq '__zb_incr' or
206      $SNAP =~ /__zb_full_\d+/ or
207      $SNAP =~ /__zb_dset_\d+/) {
208     $target .= $SNAP;
209   }
210   else {
211     die "zfs_agent_remove_snap: illegal snap: $SNAP\n";
212   }
213   `__ZFS__ destroy $target`;
214 }
215
216 sub zfs_agent_perform_full {
217   my $target = $ZFS . '@__zb_full_' . $FULL;
218   unless($ZFS && $FULL =~ /^\d+$/) {
219     die "zfs_agent_perform_full: bad fs or snap name\n"
220   }
221   `__ZFS__ snapshot $target`;
222   my @cmd = ("__ZFS__", "send", $target);
223   if($NEEDSFD) {
224     fifo_exec(@cmd);
225   } else {
226     exec { $cmd[0] } @cmd;
227   }
228   exit;
229 }
230
231 sub zfs_agent_perform_incremental {
232   my $target = $ZFS . '@__zb_incr';
233   my $base = $ZFS . '@__zb_full_' . $BASE;
234   unless($ZFS && $BASE) {
235     die "zfs_agent_perform_incremental: bad args\n"
236   }
237   `__ZFS__ snapshot $target`;
238   my @cmd = ("__ZFS__", "send", "-i", $base, $target);
239   if($NEEDSFD) {
240     fifo_exec(@cmd);
241   } else {
242     exec { $cmd[0] } @cmd;
243   }
244   exit;
245 }
246
247 sub zfs_agent_perform_dataset {
248   my $target = $ZFS . '@__zb_dset_' . $DSET;
249   my $base = $ZFS . '@__zb_dset_' . $BASE;
250   unless($ZFS && $DSET) {
251     die "zfs_agent_perform_dataset: bad args\n"
252   }
253   `__ZFS__ snapshot $target`;
254   # $BASE (the base snapshot) is optional. If provided, send an incremental
255   # snapshot
256   my @cmd;
257   if ($BASE) {
258     @cmd = ("__ZFS__", "send", "-i", $base, $target);
259   } else {
260     @cmd = ("__ZFS__", "send", $target);
261   }
262   if($NEEDSFD) {
263     fifo_exec(@cmd);
264   } else {
265     exec { $cmd[0] } @cmd;
266   }
267   exit;
268 }
269
270 sub zfs_agent_list {
271   my (%zfs, %storageclass);
272   open(ZFSLIST, "__ZFS__ list -H -t snapshot,filesystem,volume -o name,com.omniti.labs.zetaback:exclude,com.omniti.labs.zetaback:class,org.opensolaris.libbe:parentbe,org.opensolaris.libbe:uuid |");
273   # Get the UUID (if any) of the current BE, should return blank on systems
274   # where beadm isn't present
275   my $currentbe = "";
276   if($conf{exclude_inactive_be} eq '1') {
277     $currentbe = (split(/;/,`/sbin/beadm list -H 2>&1 | grep ';N'`))[1];
278   }
279   while(<ZFSLIST>) {
280     chomp;
281     my @line = split /\t/;
282     (my $fs = $line[0]) =~ s/\@.+//;
283     my $excl = $line[1];
284     my $class = $line[2];
285     my $parentbe = $line[3];
286     my $beuuid = $line[4];
287     if($conf{exclude_inactive_be} eq '1') {
288         next if ($parentbe ne '-' && $parentbe ne $currentbe);
289         next if ($beuuid ne '-' && $beuuid ne $currentbe);
290     }
291     if(($excl ne "on") && ($fs =~ /$conf{pattern}/)) {
292       if($line[0] =~ /(\S+)\@([^\@]+)$/) {
293         $zfs{$1} ||= [];
294         push @{$zfs{$1}}, $2;
295         if ($class ne "-" && $class ne "") {
296             $storageclass{$1} = $class;
297         }
298       }
299       else {
300         $zfs{$line[0]} ||= [];
301         if ($class ne "-" && $class ne "") {
302             $storageclass{$line[0]} = $class;
303         }
304       }
305     }
306   }
307   close(ZFSLIST);
308
309   foreach my $fs (sort keys %zfs) {
310     print "$fs [".join(',',@{$zfs{$fs}})."]";
311     if ($storageclass{$fs} ne "") {
312         print " {$storageclass{$fs}}";
313     }
314     print "\n";
315   }
316 }
317
318 sub zfs_agent_perform_restore {
319   unless($ZFS && $RESTORE) {
320     die "zfs_agent_perform_restore: bad state\n";
321   }
322   if($BUG_6343779) {
323     # Optionally work around Solaris bug: 6343779
324     my $base = $ZFS . '@__zb_full_' . $BUG_6343779;
325     `__ZFS__ unmount $ZFS`;
326     `__ZFS__ rollback $base`;
327   }
328   my @cmd = ("__ZFS__", "recv", $ZFS);
329   exec { $cmd[0] } @cmd;
330   exit;
331 }
332
333 sub fifo_exec {
334   my @cmd = @_;
335   my $rv = -1;
336   my $fifo = "zetaback_${$}_${FULL}${BASE}.fifo";
337   mkfifo($fifo, 0600) || die "Could not create fifo: $!";
338   my $pid = fork();
339   if($pid == 0) {
340     close(STDOUT);
341     open(STDOUT, ">$fifo") || die "Could not open fifo: $!";
342     exec { $cmd[0] } @cmd;
343     exit;
344   }
345   open(FIFO, "<$fifo");
346   unlink($fifo);
347   my $buf;
348   while(my $len = sysread(FIFO, $buf, 1024*64)) {
349     syswrite(STDOUT, $buf, $len);
350   }
351   waitpid($pid, 0);
352 }
353
354 if($LIST) { zfs_agent_list(); exit; }
355 if($ZFS && $SNAP) { zfs_agent_remove_snap(); exit; }
356 if($ZFS && $RESTORE) { zfs_agent_perform_restore(); exit; }
357 if($ZFS && $FULL) { zfs_agent_perform_full(); exit; }
358 if($ZFS && $DSET) { zfs_agent_perform_dataset(); exit; }
359 if($ZFS && $BASE) { zfs_agent_perform_incremental(); exit; }
360
361 =pod
362
363 =head1 FILES
364
365 =over
366
367 =item zetaback_agent.conf
368
369 The zetaback_agent configuration file.  The location of the file can be
370 specified on the command line with the -c flag.  The prefix of this
371 file may also be specified as an argument to the configure script.
372
373 =back
374
375 =head1 SEE ALSO
376
377 zetaback(1)
378
379 =cut
Note: See TracBrowser for help on using the browser.