1 # Copyright (c) 2010 Zmanda Inc. All Rights Reserved.
3 # This program is free software; you can redistribute it and/or modify it
4 # under the terms of the GNU General Public License version 2 as published
5 # by the Free Software Foundation.
7 # This program is distributed in the hope that it will be useful, but
8 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
9 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 # You should have received a copy of the GNU General Public License along
13 # with this program; if not, write to the Free Software Foundation, Inc.,
14 # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 # Contact information: Zmanda Inc, 465 S. Mathilda Ave., Suite 300
17 # Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
19 use Test::More tests => 11;
25 use lib "@amperldir@";
26 use Installcheck::Run;
27 use Amanda::Config qw( :init :getconf config_dir_relative );
30 use Amanda::DB::Catalog;
31 use Amanda::Recovery::Planner;
34 use Amanda::Xfer qw( :constants );
36 # and disable Debug's die() and warn() overrides
37 Amanda::Debug::disable_die_override();
39 # put the debug messages somewhere
40 Amanda::Debug::dbopen("installcheck");
41 Installcheck::log_test_output();
44 $testconf = Installcheck::Run->setup();
47 my $cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF');
48 if ($cfg_result != $CFGERR_OK) {
49 my ($level, @errors) = Amanda::Config::config_errors();
50 die(join "\n", @errors);
54 # Fill in some fake logfiles
56 my $logdir = config_dir_relative(getconf($CNF_LOGDIR));
57 my $tapelist_fn = config_dir_relative(getconf($CNF_TAPELIST));
58 my $holdingdir = "$Installcheck::TMP/holding";
59 my %holding_filenames;
63 sub make_holding_file {
64 my ($name, $dump) = @_;
66 my $dir = "$holdingdir/$dump->{dump_timestamp}";
67 my $safe_disk = $dump->{'diskname'};
68 $safe_disk =~ tr{/}{_};
69 my $filename = "$dir/$dump->{hostname}.$safe_disk";
72 # save the filename for later
73 $holding_filenames{$name} = $filename;
75 # (note that multi-chunk holding files are not used at this point)
76 my $hdr = Amanda::Header->new();
77 $hdr->{'type'} = $Amanda::Header::F_DUMPFILE;
78 $hdr->{'datestamp'} = $dump->{'dump_timestamp'};
79 $hdr->{'dumplevel'} = $dump->{'level'};
80 $hdr->{'name'} = $dump->{'hostname'};
81 $hdr->{'disk'} = $dump->{'diskname'};
82 $hdr->{'program'} = "INSTALLCHECK";
83 $hdr->{'is_partial'} = ($dump->{'status'} ne 'OK');
85 open(my $fh, ">", $filename) or die("opening '$filename': $!");
86 print $fh $hdr->to_string(32768,32768);
88 # transfer some data to that file
89 my $xfer = Amanda::Xfer->new([
90 Amanda::Xfer::Source::Pattern->new(1024*$dump->{'kb'}, "+-+-+-+-"),
91 Amanda::Xfer::Dest::Fd->new($fh),
95 my ($src, $msg, $xfer) = @_;
96 if ($msg->{type} == $XMSG_ERROR) {
97 die $msg->{elt} . " failed: " . $msg->{message};
98 } elsif ($msg->{'type'} == $XMSG_DONE) {
100 Amanda::MainLoop::quit();
103 Amanda::MainLoop::run();
109 open (my $tapelist, ">", $tapelist_fn);
112 next if (/^#/ or /^\S*$/);
115 if (/^:tapelist (\d+) (\S+)\s*$/) {
116 print $tapelist "$1 $2 reuse\n";
122 open $output, ">", "$logdir/$1" or die("Could not open $1 for writing: $!");
126 # new holding-disk file
127 if (/^:holding (\S+) (\S+) (\S+) (\S+) (\d+) (\S+) (\d+)/) {
129 'dump_timestamp' => $2, 'hostname' => $3, 'diskname' => $4,
130 'level' => $5+0, 'status' => $6, 'kb' => $7,
132 make_holding_file($1, $dump);
137 die("syntax error") if (/^:/);
151 Amanda::Recovery::Planner::make_plan(@_,
154 (my $err, $plan) = @_;
156 Amanda::MainLoop::quit();
159 Amanda::MainLoop::run();
164 return Amanda::Cmdline::dumpspec_t->new($_[0], $_[1], $_[2], $_[3]);
168 my ($got, $exp, $msg) = @_;
169 my $got_dumps = $got->{'dumps'};
171 # make an "abbreviated" version of the plan for comparison with the
174 for my $d (@$got_dumps) {
179 $d->{'dump_timestamp'},
180 "$d->{'level'}"+0, # strip bigints
183 for my $p (@{$d->{'parts'}}) {
184 next unless defined $p;
185 if (exists $p->{'holding_file'}) {
186 # extract the last two filename components, since the rest is variable
187 my $hf = $p->{'holding_file'};
188 $hf =~ s/^.*\/([^\/]*\/[^\/]*)$/$1/;
193 "$p->{filenum}"+0; # strip bigints
198 is_deeply(\@got_abbrev, $exp, $msg)
199 or diag("got:\n" . Dumper(\@got_abbrev));
202 my $changer = undef; # not needed yet
204 is_plan(make_plan_sync(
205 dumpspec => ds("no-box-at-all"),
206 changer => $changer),
208 "empty plan for nonexistent host");
210 is_plan(make_plan_sync(
211 dumpspec => ds("oldbox", "^/opt"),
212 changer => $changer),
214 [ "oldbox", "/opt", "20080414144444", 0, [
215 '20080414144444/oldbox._opt',
219 "simple plan for a dump on holding disk");
221 is_plan(make_plan_sync(
222 dumpspec => ds("somebox", "^/lib", "200801"),
223 changer => $changer),
225 [ "somebox", "/lib", "20080111000000", 0, [
230 "simple plan for just one dump");
232 is_plan(make_plan_sync(
233 dumpspec => ds("somebox", "^/lib"),
234 changer => $changer),
236 [ "somebox", "/lib", "20080111000000", 0, [
240 [ "somebox", "/lib", "20080313133333", 0, [
254 "plan for two dumps, in order by tape write time");
256 is_plan(make_plan_sync(
257 dumpspec => ds("otherbox", "^/lib"),
258 changer => $changer),
260 [ "otherbox", "/lib", "20080414144444", 1, [
261 '20080414144444/otherbox._lib',
264 [ "otherbox", "/lib", "20080313133333", 0, [
269 "plan for a two dumps, one on holding disk; holding dumps prioritized first");
271 is_plan(make_plan_sync(
273 ds("somebox", "^/lib", "20080111"),
274 ds("euclid", "/home/dustin/code/backuppc"),
276 changer => $changer),
278 [ "somebox", "/lib", "20080111000000", 0, [
282 [ "euclid", "/home/dustin/code/backuppc", "20100127172011", 0, [
292 "plan for two dumps, one of them spanned, in order by tape write time");
294 is_plan(make_plan_sync(
295 dumpspec => ds("somebox", "^/lib", "200803"),
296 one_dump_per_part => 1,
297 changer => $changer),
299 [ "somebox", "/lib", "20080313133333", 0, [
303 [ "somebox", "/lib", "20080313133333", 0, [
307 [ "somebox", "/lib", "20080313133333", 0, [
311 [ "somebox", "/lib", "20080313133333", 0, [
315 [ "somebox", "/lib", "20080313133333", 0, [
319 [ "somebox", "/lib", "20080313133333", 0, [
323 [ "somebox", "/lib", "20080313133333", 0, [
327 [ "somebox", "/lib", "20080313133333", 0, [
331 [ "somebox", "/lib", "20080313133333", 0, [
335 [ "somebox", "/lib", "20080313133333", 0, [
340 "plan for a multipart dump, one_dump_per_part");
342 is_plan(make_plan_sync(
343 dumpspec => ds("oldbox", "^/opt", "20080414144444"),
344 holding_file => $holding_filenames{'oldbox_opt_20080414144444_holding'}),
346 [ "oldbox", "/opt", "20080414144444", 0, [
347 '20080414144444/oldbox._opt',
351 "make_plan creates an appropriate plan for an explicit holding-disk recovery");
353 is_plan(make_plan_sync(
354 holding_file => $holding_filenames{'oldbox_opt_20080414144444_holding'}),
356 [ "oldbox", "/opt", "20080414144444", 0, [
357 '20080414144444/oldbox._opt',
361 "same, without a dumpspec");
363 is_plan(make_plan_sync(
364 dumpspec => ds("euclid", "/home/dustin/code/backuppc"),
366 'Conf-013' => [1, 2, 3],
367 'Conf-014' => [1, 2, 3],
369 changer => $changer),
371 [ "euclid", "/home/dustin/code/backuppc", "20100127172011", 0, [
381 "plan based on filelist, with a dumpspec");
383 is_plan(make_plan_sync(
385 'Conf-013' => [1, 2, 3],
386 'Conf-014' => [1, 2, 3],
388 changer => $changer),
390 [ "euclid", "/home/dustin/code/backuppc", "20100127172011", 0, [
400 "plan based on filelist, without a dumpspec");
403 # a short-datestamp logfile with only a single, single-part file in it
405 :tapelist 20080111 Conf-001
406 DISK planner somebox /lib
407 START planner date 20080111
408 START driver date 20080111
409 STATS driver hostname somebox
410 STATS driver startup time 0.051
411 FINISH planner date 20080111 time 82.721
412 START taper datestamp 20080111 label Conf-001 tape 1
413 SUCCESS dumper somebox /lib 20080111 0 [sec 0.209 kb 1970 kps 9382.2 orig-kb 1970]
414 SUCCESS chunker somebox /lib 20080111 0 [sec 0.305 kb 420 kps 1478.7]
415 STATS driver estimate somebox /lib 20080111 0 [sec 1 nkb 2002 ckb 480 kps 385]
416 PART taper Conf-001 1 somebox /lib 20080111 1/1 0 [sec 4.813543 kb 419 kps 87.133307]
417 DONE taper somebox /lib 20080111 1 0 [sec 4.813543 kb 419 kps 87.133307]
418 FINISH driver date 20080111 time 2167.581
420 # a logfile with several dumps in it, one of which comes in many parts, and one of which is
421 # from a previous run
422 ::: log.20080313133333.0
423 :tapelist 20080313133333 Conf-003
424 DISK planner somebox /usr/bin
425 DISK planner somebox /lib
426 DISK planner otherbox /lib
427 DISK planner otherbox /usr/bin
428 START planner date 20080313133333
429 START driver date 20080313133333
430 STATS driver hostname somebox
431 STATS driver startup time 0.059
432 INFO planner Full dump of somebox:/lib promoted from 2 days ahead.
433 FINISH planner date 20080313133333 time 0.286
434 SUCCESS dumper somebox /usr/bin 20080313133333 1 [sec 0.001 kb 20 kps 10352.0 orig-kb 20]
435 SUCCESS chunker somebox /usr/bin 20080313133333 1 [sec 1.023 kb 20 kps 50.8]
436 STATS driver estimate somebox /usr/bin 20080313133333 1 [sec 0 nkb 52 ckb 64 kps 1024]
437 START taper datestamp 20080313133333 label Conf-003 tape 1
438 PART taper Conf-003 1 somebox /usr/bin 20080313133333 1/1 1 [sec 0.000370 kb 20 kps 54054.054054]
439 DONE taper somebox /usr/bin 20080313133333 1 1 [sec 0.000370 kb 20 kps 54054.054054]
441 SUCCESS dumper somebox /lib 20080313133333 0 [sec 0.189 kb 3156 kps 50253.1 orig-kb 3156]
442 SUCCESS chunker somebox /lib 20080313133333 0 [sec 5.250 kb 3156 kps 1815.5]
443 STATS driver estimate somebox /lib 20080313133333 0 [sec 1 nkb 3156 ckb 3156 kps 9500]
444 PART taper Conf-003 2 somebox /lib 20080313133333 1/10 0 [sec 0.005621 kb 1024 kps 182173.990393]
445 PART taper Conf-003 3 somebox /lib 20080313133333 2/10 0 [sec 0.006527 kb 1024 kps 156886.777999]
446 PART taper Conf-003 4 somebox /lib 20080313133333 3/10 0 [sec 0.005854 kb 1024 kps 174923.129484]
447 PART taper Conf-003 5 somebox /lib 20080313133333 4/10 0 [sec 0.007344 kb 1024 kps 147993.746743]
448 PART taper Conf-003 6 somebox /lib 20080313133333 5/10 0 [sec 0.007344 kb 1024 kps 147993.746743]
449 PART taper Conf-003 7 somebox /lib 20080313133333 6/10 0 [sec 0.007344 kb 1024 kps 147993.746743]
450 PART taper Conf-003 8 somebox /lib 20080313133333 7/10 0 [sec 0.007344 kb 1024 kps 147993.746743]
451 PART taper Conf-003 9 somebox /lib 20080313133333 8/10 0 [sec 0.007344 kb 1024 kps 147993.746743]
452 PART taper Conf-003 10 somebox /lib 20080313133333 9/10 0 [sec 0.007344 kb 1024 kps 147993.746743]
453 PART taper Conf-003 11 somebox /lib 20080313133333 10/10 0 [sec 0.001919 kb 284 kps 147993.746743]
454 DONE taper somebox /lib 20080313133333 10 0 [sec 0.051436 kb 3156 kps 184695.543977]
455 SUCCESS dumper otherbox /lib 20080313133333 0 [sec 0.001 kb 190 kps 10352.0 orig-kb 20]
456 SUCCESS chunker otherbox /lib 20080313133333 0 [sec 1.023 kb 190 kps 50.8]
457 STATS driver estimate otherbox /lib 20080313133333 0 [sec 0 nkb 190 ckb 190 kps 1024]
458 # this dump is from a previous run, with an older dump_timestamp
459 PART taper Conf-003 12 otherbox /usr/bin 20080311131133 1/1 0 [sec 0.002733 kb 240 kps 136425.648022]
460 DONE taper otherbox /usr/bin 20080311131133 1 0 [sec 0.002733 kb 240 kps 136425.648022]
461 PART taper Conf-003 13 otherbox /lib 20080313133333 1/1 0 [sec 0.001733 kb 190 kps 136425.648022]
462 DONE taper otherbox /lib 20080313133333 1 0 [sec 0.001733 kb 190 kps 136425.648022]
463 FINISH driver date 20080313133333 time 24.777
465 # A logfile with some partial parts (PARTPARTIAL) in it
466 ::: log.20080414144444.0
467 :tapelist 20080414144444 Conf-004
468 :tapelist 20080414144444 Conf-005
469 DISK planner otherbox /lib
470 START planner date 20080414144444
471 START driver date 20080414144444
472 STATS driver hostname otherbox
473 STATS driver startup time 0.075
474 INFO taper Will write new label `Conf-004' to new (previously non-amanda) tape
475 FINISH planner date 20080414144444 time 2.139
476 SUCCESS dumper otherbox /lib 20080414144444 1 [sec 0.003 kb 60 kps 16304.3 orig-kb 60]
477 SUCCESS chunker otherbox /lib 20080414144444 1 [sec 1.038 kb 60 kps 88.5]
478 STATS driver estimate otherbox /lib 20080414144444 1 [sec 0 nkb 92 ckb 96 kps 1024]
479 START taper datestamp 20080414144444 label Conf-004 tape 1
480 PARTPARTIAL taper Conf-004 1 otherbox /lib 20080414144444 1/1 1 [sec 0.000707 kb 32 kps 45261.669024] ""
481 INFO taper Will request retry of failed split part.
482 INFO taper Will write new label `Conf-005' to new (previously non-amanda) tape
483 START taper datestamp 20080414144444 label Conf-005 tape 2
484 PARTPARTIAL taper Conf-005 1 otherbox /lib 20080414144444 1/1 1 [sec 0.000540 kb 32 kps 59259.259259] ""
485 INFO taper Will request retry of failed split part.
486 WARNING driver Out of tapes; going into degraded mode.
487 PARTIAL taper otherbox /lib 20080414144444 1 1 [sec 0.000540 kb 32 kps 59259.259259] "full-up"
488 # a completely failed dump
489 FAIL taper otherbox /boot 20080414144444 0 "no-space"
490 FINISH driver date 20080414144444 time 6.959
492 # a spanned dump (yep, a real dump)
493 ::: log.20100127172011.0
494 :tapelist 20100127172011 Conf-013
495 :tapelist 20100127172011 Conf-014
496 INFO amdump amdump pid 30186
497 INFO planner planner pid 30207
498 START planner date 20100127172011
499 DISK planner euclid /home/dustin/code/backuppc
500 INFO planner Adding new disk euclid:/home/dustin/code/backuppc.
501 INFO driver driver pid 30208
502 START driver date 20100127172011
503 STATS driver hostname euclid
504 INFO dumper dumper pid 30220
505 STATS driver startup time 0.097
506 INFO dumper dumper pid 30222
507 INFO dumper dumper pid 30221
508 INFO dumper dumper pid 30213
509 INFO taper taper pid 30210
510 FINISH planner date 20100127172011 time 1.224
511 INFO planner pid-done 30207
512 INFO taper Will write new label `Conf-013' to new tape
513 INFO chunker chunker pid 30255
514 INFO dumper gzip pid 30259
515 SUCCESS dumper euclid /home/dustin/code/backuppc 20100127172011 0 [sec 0.933 kb 2770 kps 2968.5 orig-kb 2770]
516 SUCCESS chunker euclid /home/dustin/code/backuppc 20100127172011 0 [sec 0.943 kb 2770 kps 2970.1]
517 INFO chunker pid-done 30255
518 STATS driver estimate euclid /home/dustin/code/backuppc 20100127172011 0 [sec 2 nkb 2802 ckb 2816 kps 1024]
519 INFO dumper pid-done 30259
520 START taper datestamp 20100127172011 label Conf-013 tape 1
521 PART taper Conf-013 1 euclid /home/dustin/code/backuppc 20100127172011 1/-1 0 [sec 0.000763 kb 512 kps 670972.950092]
522 PART taper Conf-013 2 euclid /home/dustin/code/backuppc 20100127172011 2/-1 0 [sec 0.000770 kb 512 kps 664770.167400]
523 PART taper Conf-013 3 euclid /home/dustin/code/backuppc 20100127172011 3/-1 0 [sec 0.000877 kb 512 kps 583952.261903]
524 PARTPARTIAL taper Conf-013 4 euclid /home/dustin/code/backuppc 20100127172011 4/-1 0 [sec 0.000689 kb 352 kps 510888.307044] "No space left on device"
525 INFO taper Will request retry of failed split part.
526 INFO taper tape Conf-013 kb 1536 fm 4 [OK]
527 INFO taper Will write new label `Conf-014' to new tape
528 START taper datestamp 20100127172011 label Conf-014 tape 2
529 PART taper Conf-014 1 euclid /home/dustin/code/backuppc 20100127172011 4/-1 0 [sec 0.001346 kb 512 kps 380377.004130]
530 PART taper Conf-014 2 euclid /home/dustin/code/backuppc 20100127172011 5/-1 0 [sec 0.001338 kb 512 kps 382524.888399]
531 PART taper Conf-014 3 euclid /home/dustin/code/backuppc 20100127172011 6/-1 0 [sec 0.000572 kb 210 kps 367336.443449]
532 DONE taper euclid /home/dustin/code/backuppc 20100127172011 6 0 [sec 0.005666 kb 2770 kps 488860.596548]
533 INFO dumper pid-done 30213
534 INFO dumper pid-done 30220
535 INFO dumper pid-done 30222
536 INFO taper tape Conf-014 kb 1234 fm 3 [OK]
537 INFO dumper pid-done 30221
538 INFO taper pid-done 30210
539 FINISH driver date 20100127172011 time 4.197
540 INFO driver pid-done 30208
543 :holding otherbox_lib_20080414144444_holding 20080414144444 otherbox /lib 1 OK 256
544 :holding oldbox_opt_20080414144444_holding 20080414144444 oldbox /opt 0 OK 1298