b8a3971fe6db89355bedd67b3f89d7050470513a
[debian/amanda] / installcheck / amvault.pl
1 # Copyright (c) 2010 Zmanda, Inc.  All Rights Reserved.
2 #
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.
6 #
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
10 # for more details.
11 #
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
15 #
16 # Contact information: Zmanda Inc, 465 S. Mathilda Ave., Suite 300
17 # Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
18
19 use Test::More tests => 11;
20 use strict;
21 use warnings;
22
23 use lib "@amperldir@";
24 use File::Path;
25 use Data::Dumper;
26 use Installcheck;
27 use Installcheck::Dumpcache;
28 use Installcheck::Config;
29 use Installcheck::Mock;
30 use Installcheck::Run qw(run run_err run_get $diskname);
31 use Amanda::DB::Catalog;
32 use Amanda::Paths;
33 use Amanda::Config qw( :init );
34 use Amanda::Changer;
35 use Amanda::Debug;
36
37 Amanda::Debug::dbopen("installcheck");
38
39 my $vtape_root = "$Installcheck::TMP/tertiary";
40 sub setup_chg_disk {
41     rmtree $vtape_root if -d $vtape_root;
42     mkpath "$vtape_root/slot1";
43     return "chg-disk:$vtape_root";
44 }
45
46 # set up a basic dump
47 Installcheck::Dumpcache::load("basic");
48
49 config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF");
50 my ($cfgerr_level, @cfgerr_errors) = config_errors();
51 if ($cfgerr_level >= $CFGERR_WARNINGS) {
52     config_print_errors();
53     die "config errors";
54 }
55
56 # and then set up a new vtape to vault onto
57 my $tertiary_chg = setup_chg_disk();
58
59 # try a few failures first
60 like(run_err("$sbindir/amvault",
61                 '--autolabel=any',
62                 '--label-template', "TESTCONF%%",
63                 '--src-timestamp', 'latest',
64                 '--dst-changer', $tertiary_chg,
65                 'TESTCONF', 'someotherhost'),
66     qr/No dumps to vault/,
67     "amvault with a non-matching dumpspec dumps nothing")
68     or diag($Installcheck::Run::stderr);
69
70 like(run_err("$sbindir/amvault",
71                 '--autolabel=any',
72                 '--label-template', "TESTCONF%%",
73                 '--src-timestamp', 'latest',
74                 '--fulls-only',
75                 '--dst-changer', $tertiary_chg,
76                 'TESTCONF', '*', '*', '*', '1-3'),
77     qr/No dumps to vault/,
78     "amvault with --fulls-only but specifying non-full dumpspecs dumps nothing")
79     or diag($Installcheck::Run::stderr);
80
81 like(run_err("$sbindir/amvault",
82                 '--autolabel=any',
83                 '--label-template', "TESTCONF%%",
84                 '--dst-changer', $tertiary_chg,
85                 'TESTCONF'),
86     qr/specify something to select/,
87     "amvault without any limiting factors is an error"),
88     or diag($Installcheck::Run::stderr);
89
90 # now a successful vaulting
91 ok(run("$sbindir/amvault",
92                 '--autolabel=any',
93                 '--label-template', "TESTCONF%%",
94                 '--src-timestamp', 'latest',
95                 '--dst-changer', $tertiary_chg,
96                 'TESTCONF'),
97     "amvault runs!")
98     or diag($Installcheck::Run::stderr);
99 my @tert_files = glob("$vtape_root/slot1/0*");
100 ok(@tert_files > 0,
101     "..and files appear on the tertiary volume!");
102
103 my @dumps = Amanda::DB::Catalog::sort_dumps([ 'write_timestamp' ],
104         Amanda::DB::Catalog::get_dumps());
105
106 is(scalar @dumps, 2,
107     "now there are two dumps in the catalog");
108
109 sub summarize {
110     my ($dump) = @_;
111     return {
112         map { $_ => $dump->{$_} }
113             qw(diskname hostname level dump_timestamp kb orig_kb)
114     };
115 }
116 is_deeply(summarize($dumps[1]), summarize($dumps[0]),
117     "and they match in all the right ways")
118     or diag(Dumper(@dumps));
119
120 # clean up the tertiary vtapes before moving on
121 rmtree $vtape_root;
122 Installcheck::Run::cleanup();
123
124 # try the multi dump, to get a better idea of the filtering possibilities
125 Installcheck::Dumpcache::load("multi");
126 config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF");
127 ($cfgerr_level, @cfgerr_errors) = config_errors();
128 if ($cfgerr_level >= $CFGERR_WARNINGS) {
129     config_print_errors();
130     die "config errors";
131 }
132
133 sub get_dry_run {
134     my $stdout = run_get(@_);
135     if (!$stdout) {
136         diag($Installcheck::Run::stderr);
137         return 'run-failed';
138     }
139
140     my @rv;
141     for my $line (split /\n/, $stdout) {
142         next if ($line =~ /^Total Size:/);
143         my ($tape, $file, $host, $disk, $datestamp, $level) =
144             ($line =~ /^(\S+) (\d*) (\S+) (.+) (\d+) (\d+)$/);
145         $tape = 'holding' if $file eq '';
146         push @rv, [$tape, $file, $host, $disk,   $level]; # note: no datestamp
147     }
148     return @rv;
149 }
150
151 is_deeply([ get_dry_run("$sbindir/amvault",
152                 '--dry-run',
153                 '--autolabel=any',
154                 '--label-template', "TESTCONF%%",
155                 '--fulls-only',
156                 '--dst-changer', $tertiary_chg,
157                 'TESTCONF') ], [
158     [ "TESTCONF01", "1", "localhost", "$diskname/dir", "0" ],
159     [ "TESTCONF01", "2", "localhost", "$diskname",     "0" ],
160     [ "TESTCONF02", "2", "localhost", "$diskname",     "0" ]
161     ], "amvault with --fulls-only only dumps fulls");
162
163 is_deeply([ get_dry_run("$sbindir/amvault",
164                 '--dry-run',
165                 '--autolabel=any',
166                 '--label-template', "TESTCONF%%",
167                 '--dst-changer', $tertiary_chg,
168                 'TESTCONF', "localhost", "$diskname/dir") ], [
169     [ "holding", "",     "localhost", "$diskname/dir",     "1" ],
170     [ "TESTCONF01", "1", "localhost", "$diskname/dir",     "0" ],
171     [ "TESTCONF02", "1", "localhost", "$diskname/dir",     "1" ]
172     ], "amvault with a disk expression dumps only that disk");
173
174 # Test NDMP-to-NDMP vaulting.  This will test all manner of goodness:
175 #  - specifying a named changer on the amvault command line
176 #  - exporting
177 #  - directtcp vaulting (well, not really, since we don't support connecting yet)
178 SKIP: {
179     skip "not built with ndmp and server", 2 unless
180         Amanda::Util::built_with_component("ndmp") and Amanda::Util::built_with_component("server");
181
182     Installcheck::Dumpcache::load("ndmp");
183
184     my $ndmp = Installcheck::Mock::NdmpServer->new(no_reset => 1);
185     $ndmp->edit_config();
186
187     # append a tertiary changer to the config file - it's just too hard to
188     # specify a full ndmp changer on the command line
189
190     my $ndmp_port = $ndmp->{'port'};
191     my $chg_dir = "$Installcheck::TMP/vtapes/ndmjob-tert";
192     my $chg_spec = "chg-ndmp:127.0.0.1:$ndmp_port\@$chg_dir";
193     my $drive_root = "ndmp:127.0.0.1:$ndmp_port\@$chg_dir";
194
195     -d $chg_dir && rmtree($chg_dir);
196     mkpath($chg_dir);
197
198     my $amanda_conf_filename = "$CONFIG_DIR/TESTCONF/amanda.conf";
199     open(my $fh, ">>", $amanda_conf_filename);
200     print $fh <<EOF;
201 define changer "tertiary" {
202     tpchanger "$chg_spec"
203     property        "tape-device" "0=$drive_root/drive0"
204     property append "tape-device" "1=$drive_root/drive1"
205     changerfile "$chg_dir-changerfile"
206 }
207 EOF
208
209     $tertiary_chg = "tertiary";
210     ok(run("$sbindir/amvault",
211                     '--export',
212                     '--autolabel=any',
213                     '--label-template', "TESTCONF%%",
214                     '--src-timestamp', 'latest',
215                     '--dst-changer', $tertiary_chg,
216                     'TESTCONF'),
217         "amvault runs with an NDMP device as secondary and tertiary, with --export")
218         or diag($Installcheck::Run::stderr);
219
220     config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF");
221     ($cfgerr_level, @cfgerr_errors) = config_errors();
222     if ($cfgerr_level >= $CFGERR_WARNINGS) {
223         config_print_errors();
224         die "config errors";
225     }
226
227     # query the tertiary changer to see where that dump ended up
228     my $chg = Amanda::Changer->new($tertiary_chg);
229     my $inventory;
230     my $inventory_cb = sub {
231         my ($err, $inv) = @_;
232         die "$err" if $err;
233
234         $inventory = $inv;
235         Amanda::MainLoop::quit();
236     };
237     Amanda::MainLoop::call_later(sub { $chg->inventory(inventory_cb => $inventory_cb); });
238     Amanda::MainLoop::run();
239     $chg->quit();
240
241     # find TESTCONF02 in the inventory, and check that it is in an i/e slot
242     my $notfound = "tertiary volume not found";
243     for my $i (@$inventory) {
244         if ($i->{'label'} && $i->{'label'} eq 'TESTCONF02') {
245             if ($i->{'import_export'}) {
246                 $notfound = undef;
247             } else {
248                 $notfound = "tertiary volume not properly exported";
249             }
250             #last;
251         }
252     }
253
254     ok(!$notfound, "tertiary volume exists and was properly exported");
255     if ($notfound) {
256         diag($notfound);
257         diag("amvault stderr:");
258         diag($Installcheck::Run::stderr);
259     }
260
261 }
262
263 # clean up
264 Installcheck::Run::cleanup();