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