root/zetaback_agent.in

Revision a3009c9cdc5df4d09f671ab6eae9afedb27a8e2f, 8.4 kB (checked in by Mark Harrison <mark@mivok.net>, 2 years ago)

Go back to manually specifying a version number

The automated version was svn specific and was broken in the change to git.

  • 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 =head1 CONFIGURATION EXAMPLES
151
152 =head2 All ZFS filesystems
153
154 This pattern matches all ZFS filesystems.
155
156   pattern=.
157
158 =head2 Substring match
159
160 This will match anywhere in the name of the ZFS filesystem.  This is
161 helpful for catching all ZFS filesystems in a particular zpool, while
162 excluding any others.
163
164   pattern=zones
165
166 =head2 Left-anchored names
167
168 This pattern matches all ZFS filesystems whose names begin with 'www'.
169
170   pattern=^www
171
172 =head2 Specific ZFS filesystems
173
174 This pattern matches specific ZFS filesystems.
175
176   pattern=(?:data|mirrors|www)
177
178 =head2 Combining with property-based exclude
179
180 All filesystems in pool 'zones' except 'foo'
181
182   pattern=^zones
183
184   (At a root shell or with pfexec/sudo):
185   zfs set com.omniti.labs.zetaback:exclude=on zones/foo
186
187 =cut
188
189 # Read our config in
190 $conf{pattern} = '.';
191 open(CONF, "<$CONF");
192 while(<CONF>) { /^\s*([^#](?:\S*)?)\s*=\s*(\S+)/ && ($conf{lc($1)} = $2); }
193 close(CONF);
194
195 sub zfs_agent_remove_snap {
196   my $target = $ZFS . '@';
197   die "zfs_agent_remove_snap: insufficient args\n" unless($ZFS && $SNAP);
198   if($SNAP eq '__zb_incr' or
199      $SNAP =~ /__zb_full_\d+/ or
200      $SNAP =~ /__zb_dset_\d+/) {
201     $target .= $SNAP;
202   }
203   else {
204     die "zfs_agent_remove_snap: illegal snap: $SNAP\n";
205   }
206   `__ZFS__ destroy $target`;
207 }
208
209 sub zfs_agent_perform_full {
210   my $target = $ZFS . '@__zb_full_' . $FULL;
211   unless($ZFS && $FULL =~ /^\d+$/) {
212     die "zfs_agent_perform_full: bad fs or snap name\n"
213   }
214   `__ZFS__ snapshot $target`;
215   my @cmd = ("__ZFS__", "send", $target);
216   if($NEEDSFD) {
217     fifo_exec(@cmd);
218   } else {
219     exec { $cmd[0] } @cmd;
220   }
221   exit;
222 }
223
224 sub zfs_agent_perform_incremental {
225   my $target = $ZFS . '@__zb_incr';
226   my $base = $ZFS . '@__zb_full_' . $BASE;
227   unless($ZFS && $BASE) {
228     die "zfs_agent_perform_incremental: bad args\n"
229   }
230   `__ZFS__ snapshot $target`;
231   my @cmd = ("__ZFS__", "send", "-i", $base, $target);
232   if($NEEDSFD) {
233     fifo_exec(@cmd);
234   } else {
235     exec { $cmd[0] } @cmd;
236   }
237   exit;
238 }
239
240 sub zfs_agent_perform_dataset {
241   my $target = $ZFS . '@__zb_dset_' . $DSET;
242   my $base = $ZFS . '@__zb_dset_' . $BASE;
243   unless($ZFS && $DSET) {
244     die "zfs_agent_perform_dataset: bad args\n"
245   }
246   `__ZFS__ snapshot $target`;
247   # $BASE (the base snapshot) is optional. If provided, send an incremental
248   # snapshot
249   my @cmd;
250   if ($BASE) {
251     @cmd = ("__ZFS__", "send", "-i", $base, $target);
252   } else {
253     @cmd = ("__ZFS__", "send", $target);
254   }
255   if($NEEDSFD) {
256     fifo_exec(@cmd);
257   } else {
258     exec { $cmd[0] } @cmd;
259   }
260   exit;
261 }
262
263 sub zfs_agent_list {
264   my (%zfs, %storageclass);
265   open(ZFSLIST, "__ZFS__ list -H -t snapshot,filesystem,volume |");
266   while(<ZFSLIST>) {
267     chomp;
268     my @line = split /\t/;
269     (my $fs = $line[0]) =~ s/\@.+//;
270     my $excl = (split(/\s+/,`__ZFS__ get -H com.omniti.labs.zetaback:exclude $fs 2>/dev/null`))[2];
271     my $class = (split(/\s+/,`__ZFS__ get -H com.omniti.labs.zetaback:class $fs 2>/dev/null`))[2];
272     if(($excl ne "on") && ($fs =~ /$conf{pattern}/)) {
273       if($line[0] =~ /(\S+)\@([^\@]+)$/) {
274         $zfs{$1} ||= [];
275         push @{$zfs{$1}}, $2;
276         if ($class ne "-" && $class ne "") {
277             $storageclass{$1} = $class;
278         }
279       }
280       else {
281         $zfs{$line[0]} ||= [];
282         if ($class ne "-" && $class ne "") {
283             $storageclass{$line[0]} = $class;
284         }
285       }
286     }
287   }
288   close(ZFSLIST);
289
290   foreach my $fs (sort keys %zfs) {
291     print "$fs [".join(',',@{$zfs{$fs}})."]";
292     if ($storageclass{$fs} ne "") {
293         print " {$storageclass{$fs}}";
294     }
295     print "\n";
296   }
297 }
298
299 sub zfs_agent_perform_restore {
300   unless($ZFS && $RESTORE) {
301     die "zfs_agent_perform_restore: bad state\n";
302   }
303   if($BUG_6343779) {
304     # Optionally work around Solaris bug: 6343779
305     my $base = $ZFS . '@__zb_full_' . $BUG_6343779;
306     `__ZFS__ unmount $ZFS`;
307     `__ZFS__ rollback $base`;
308   }
309   my @cmd = ("__ZFS__", "recv", $ZFS);
310   exec { $cmd[0] } @cmd;
311   exit;
312 }
313
314 sub fifo_exec {
315   my @cmd = @_;
316   my $rv = -1;
317   my $fifo = "zetaback_${$}_${FULL}${BASE}.fifo";
318   mkfifo($fifo, 0600) || die "Could not create fifo: $!";
319   my $pid = fork();
320   if($pid == 0) {
321     close(STDOUT);
322     open(STDOUT, ">$fifo") || die "Could not open fifo: $!";
323     exec { $cmd[0] } @cmd;
324     exit;
325   }
326   open(FIFO, "<$fifo");
327   unlink($fifo);
328   my $buf;
329   while(my $len = sysread(FIFO, $buf, 1024*64)) {
330     syswrite(STDOUT, $buf, $len);
331   }
332   waitpid($pid, 0);
333 }
334
335 if($LIST) { zfs_agent_list(); exit; }
336 if($ZFS && $SNAP) { zfs_agent_remove_snap(); exit; }
337 if($ZFS && $RESTORE) { zfs_agent_perform_restore(); exit; }
338 if($ZFS && $FULL) { zfs_agent_perform_full(); exit; }
339 if($ZFS && $DSET) { zfs_agent_perform_dataset(); exit; }
340 if($ZFS && $BASE) { zfs_agent_perform_incremental(); exit; }
341
342 =pod
343
344 =head1 FILES
345
346 =over
347
348 =item zetaback_agent.conf
349
350 The zetaback_agent configuration file.  The location of the file can be
351 specified on the command line with the -c flag.  The prefix of this
352 file may also be specified as an argument to the configure script.
353
354 =back
355
356 =head1 SEE ALSO
357
358 zetaback(1)
359
360 =cut
Note: See TracBrowser for help on using the browser.