Imported Upstream version 3.2.0
[debian/amanda] / installcheck / Installcheck / Dumpcache.pm
1 # Copyright (c) 2008, 2009, 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 package Installcheck::Dumpcache;
20
21 =head1 NAME
22
23 Installcheck::Dumpcache - manage a cached amdump run, to avoid the need to run
24 amdump repeatedly just to test other applications
25
26 =head1 SYNOPSIS
27
28   use Installcheck::Dumpcache;
29
30   Installcheck::Dumpcache::load("basic");
31
32 =head1 DESCRIPTION
33
34 This single function will make an amdump run, or at least make it look like one
35 has been done by restoring a cached tarball of a previous run.  This saves the
36 time of repeated slow 'amdump' invocations to test functionality that requires
37 an existing dump.
38
39 The dump cache captures everything: vtapes, curinfo, indexes, trace logs,
40 tapelist, timestamp, and configuration.  When a flavor is loaded, the timestamp
41 for all runs are available in the package variable C<@timestamps>.
42
43 The function C<create_all> is called by the special installcheck '=setupcache',
44 and fills the cache.
45
46 =head1 FLAVORS
47
48 =head2 basic
49
50 Basic runs a single amdump with the default L<Installcheck::Run> configuration,
51 to which has been added:
52
53   $testconf->add_dle("localhost $diskname installcheck-test");
54
55 and a few basic configuration parameters listed below.
56
57 =head2 notimestamps
58
59 Like 'basic', but with "usetimestamps" set to "no".
60
61 =head2 ndmp
62
63 Like 'basic', but with an NDMP device.  You will need to use
64 L<Installcheck::Mock>'s C<edit_config> to use this.
65
66 =head2 parts
67
68 A single multi-part dump with nine parts (using a fallback_splitsize of 128k).
69
70 =head2 compress
71
72 A single dump of C<$diskname> with server-side compression enabled.  This 
73
74 =head2 multi
75
76 This flavor runs three dumps of two DLEs (C<$diskname> and C<$diskname/dir>).
77 The first two dumps run normally, while the third is in degraded mode (the
78 taper is disabled).
79
80 =cut
81
82 use Installcheck;
83 use Installcheck::Run qw(run $diskname $taperoot amdump_diag);
84 use Installcheck::Mock;
85 use Test::More;
86 use Amanda::Paths;
87 use Amanda::Constants;
88 use File::Path qw( mkpath rmtree );
89 use IPC::Open3;
90 use Cwd qw(abs_path getcwd);
91 use Carp;
92
93 our @timestamps;
94
95 my $tarballdir = "$Installcheck::TMP/dumpcache";
96 my %flavors;
97
98 sub basic_settings {
99     my ($testconf) = @_;
100
101     $testconf->add_param('autolabel', '"TESTCONF%%" EMPTY VOLUME_ERROR');
102     $testconf->add_param('amrecover_changer', '"changer"');
103 }
104
105 sub use_new_chg_disk {
106     my ($testconf) = @_;
107
108     $testconf->remove_param('tapedev');
109     $testconf->remove_param('tpchanger');
110     $testconf->add_param('tpchanger', "\"chg-disk:$taperoot\"");
111 }
112
113 $flavors{'basic'} = sub {
114     my $testconf = Installcheck::Run::setup();
115     basic_settings($testconf);
116     use_new_chg_disk($testconf);
117     $testconf->add_dle("localhost $diskname installcheck-test");
118     $testconf->write();
119
120     ok(Installcheck::Run::run('amdump', 'TESTCONF'), "amdump for 'basic'"),
121         or amdump_diag("Amdump run failed for 'basic'");
122 };
123
124 $flavors{'notimestamps'} = sub {
125     my $testconf = Installcheck::Run::setup();
126     basic_settings($testconf);
127     use_new_chg_disk($testconf);
128     $testconf->add_dle("localhost $diskname installcheck-test");
129     $testconf->add_param('usetimestamps', 'no');
130     $testconf->write();
131
132     ok(Installcheck::Run::run('amdump', 'TESTCONF'), "amdump for 'notimestamps'"),
133         or amdump_diag("Amdump run failed for 'notimestamps'");
134 };
135
136 $flavors{'multi'} = sub {
137     my $stuff = "abcdefghijkl" x 512;
138     my $append_stuff = sub {
139         open(my $fh, ">>", "$diskname/extrastuff");
140         print $fh $stuff, $stuff;
141         close($fh);
142
143         open($fh, ">>", "$diskname/dir/extrastuff");
144         print $fh $stuff, $stuff;
145         close($fh);
146     };
147
148     my $testconf = Installcheck::Run::setup();
149     basic_settings($testconf);
150     use_new_chg_disk($testconf);
151     $testconf->add_dle("localhost $diskname installcheck-test");
152     $testconf->add_dle("localhost $diskname/dir installcheck-test");
153     # do the smallest dumps first -- $diskname/dir in particular should
154     # be smaller than $diskname
155     $testconf->add_param("dumporder", '"ssssssssss"');
156     $testconf->write();
157
158     ok(Installcheck::Run::run('amdump', 'TESTCONF'), "amdump for 'multi' step 1"),
159         or amdump_diag("Amdump run failed for 'multi' step 1");
160
161     $append_stuff->();
162
163     # XXX note that Amanda will not bump $diskname to level 1 here; other installchecks
164     # may depend on this behavior
165     ok(Installcheck::Run::run('amdump', 'TESTCONF'), "amdump for 'multi' step 2"),
166         or amdump_diag("Amdump run failed for 'multi' step 2");
167
168     $append_stuff->();
169
170     ok(Installcheck::Run::run('amdump', 'TESTCONF', '-otpchanger=', '-otapedev='),
171         "amdump for 'multi' step 3 (degraded mode)"),
172         or amdump_diag("Amdump run failed for 'multi' step 3 (degraded mode)");
173
174     # we made a mess of $diskname, so invalidate it
175     rmtree("$diskname");
176 };
177
178 $flavors{'parts'} = sub {
179     my $testconf = Installcheck::Run::setup();
180     basic_settings($testconf);
181     use_new_chg_disk($testconf);
182     $testconf->add_tapetype("TEST-TAPE", [
183         "length", "50M",
184         "part_size", "128k",
185         "part_cache_type", "memory",
186     ]);
187     $testconf->add_dle("localhost $diskname installcheck-test");
188     $testconf->write();
189
190     ok(Installcheck::Run::run('amdump', 'TESTCONF'), "amdump for 'parts'"),
191         or amdump_diag("Amdump run failed for 'part'");
192 };
193
194 $flavors{'compress'} = sub {
195     my $testconf = Installcheck::Run::setup();
196     basic_settings($testconf);
197     use_new_chg_disk($testconf);
198     $testconf->add_dumptype("installcheck-test-comp", [
199         "installcheck-test", "",
200         "compress", "server fast",
201     ]);
202     $testconf->add_dle("localhost $diskname installcheck-test-comp");
203     $testconf->write();
204
205     # add some compressible data to the dump
206     open(my $fh, ">>", "$diskname/compressible");
207     my $stuff = <<EOLOREM;
208 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
209 incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
210 nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
211 Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
212 fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
213 culpa qui officia deserunt mollit anim id est laborum.
214 EOLOREM
215     for my $i (1 .. 100) {
216         print $fh $stuff, $stuff;
217     }
218     close($fh);
219
220     ok(Installcheck::Run::run('amdump', 'TESTCONF'), "amdump for 'compress'"),
221         or amdump_diag("Amdump run failed for 'part'");
222
223     # we made a mess of $diskname, so invalidate it
224     rmtree("$diskname");
225 };
226
227 if (Amanda::Util::built_with_component("server")
228     and Amanda::Util::built_with_component("ndmp")) {
229
230     $flavors{'ndmp'} = sub {
231         my $testconf = Installcheck::Run::setup();
232         basic_settings($testconf);
233         use_new_chg_disk($testconf);
234         $testconf->add_dle("localhost $diskname installcheck-test");
235         my $ndmp = Installcheck::Mock::NdmpServer->new();
236         $ndmp->config($testconf);
237         $testconf->write();
238
239         ok(Installcheck::Run::run('amdump', 'TESTCONF'), "amdump for 'ndmp'"),
240             or amdump_diag("Amdump run failed for 'ndmp'");
241     };
242 }
243
244 sub generate_and_store {
245     my ($flavor) = @_;
246
247     if (exists $flavors{$flavor}) {
248         $flavors{$flavor}->();
249     } else {
250         die("Invalid flavor '$flavor'");
251     }
252
253     # now package that up as a tarball
254     mkpath($tarballdir);
255     my $tmp_tarball = "$tarballdir/$flavor-tmp.tgz";
256     my $conf_tarball = "$tarballdir/$flavor-conf.tgz";
257
258     if (system("$Amanda::Constants::GNUTAR",
259                 "-C", "$Installcheck::TMP",
260                 "-zcf", "$tmp_tarball",
261                 "vtapes",
262                 "holding")) {
263         diag("Error caching dump results (ignored): $?");
264         return 0;
265     }
266
267     if (system("$Amanda::Constants::GNUTAR",
268                 "-C", "$CONFIG_DIR",
269                 "-zcf", "$conf_tarball",
270                 "TESTCONF")) {
271         diag("Error caching dump results (ignored): $?");
272         return 0;
273     }
274
275     return 1;
276 }
277
278 sub load {
279     my ($flavor) = @_;
280
281     croak("Invalid flavor '$flavor'") unless (exists $flavors{$flavor});
282
283     # clean up any remnants first
284     Installcheck::Run::cleanup();
285
286     my $tmp_tarball = "$tarballdir/$flavor-tmp.tgz";
287     my $conf_tarball = "$tarballdir/$flavor-conf.tgz";
288
289     if (! -f $tmp_tarball || ! -f $conf_tarball) {
290         die "Cached dump '$flavor' is not available.  Re-run the '=setupcache' check";
291     }
292     if (system("$Amanda::Constants::GNUTAR",
293                 "-zxf", "$tmp_tarball",
294                 "-C", "$Installcheck::TMP")) {
295         die("Error untarring dump results: $?");
296     }
297
298     if (system("$Amanda::Constants::GNUTAR",
299                 "-zxf", "$conf_tarball",
300                 "-C", "$CONFIG_DIR")) {
301         die("Error untarring dump results: $?");
302     }
303
304     # calculate the timestamps for this run
305     my @logfiles = glob "$CONFIG_DIR/TESTCONF/log/log.*";
306     my %timestamps = map { my ($ts) = ($_ =~ /log\.(\d+)\./); $ts?($ts, 1):() } @logfiles;
307     @timestamps = keys %timestamps; # set package variable
308 }
309
310 sub create_all {
311     for my $flavor (keys %flavors) {
312         ok(generate_and_store($flavor), "cached flavor '$flavor'") or return;
313     }
314 }
315
316 Installcheck::Run::cleanup();
317
318 1;