2 # Copyright (c) 2008-2012 Zmanda, Inc. All Rights Reserved.
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
9 # This program is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 # You should have received a copy of the GNU General Public License along
15 # with this program; if not, write to the Free Software Foundation, Inc.,
16 # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 # Contact information: Zmanda Inc, 465 S. Mathilda Ave., Suite 300
19 # Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
21 package Installcheck::Config;
24 use Amanda::Constants;
30 Installcheck::Config - set up amanda configurations for installcheck testing
34 use Installcheck::Config;
36 my $testconf = Installcheck::Config->new();
37 $testconf->add_param("runtapes", "5");
38 $testconf->add_tapetype("DUCKTAPE", [
39 length => "10G", filemark => "4096k",
44 The resulting configuration is always named "TESTCONF". The basic
45 configuration contains only a few parameters that are necessary
46 just to run Amanda applications in the test environment. It also
47 contains a tapetype, C<TEST-TAPE>. To change tapetype parameters,
48 call C<< $cf->add_tapetype >> with a new definition of C<TEST-TAPE>.
50 Note that it's quite possible to produce an invalid configuration with this
51 package (and, in fact, some of the tests do just that).
55 Using this module I<will> destroy any existing configuration named
56 TESTDIR. I<Please> do not use this on a production machine!
64 Create a new configuration object
71 # An instance is a blessed hash containing parameters. Start with
72 # some defaults to make sure things run.
73 my $infofile = "$CONFIG_DIR/TESTCONF/curinfo";
74 my $logdir = "$CONFIG_DIR/TESTCONF/log";
75 my $indexdir = "$CONFIG_DIR/TESTCONF/index";
76 my $org = "DailySet1";
79 'infofile' => $infofile,
81 'indexdir' => $indexdir,
83 # Global params are stored as an arrayref, so that the same declaration
84 # can appear multiple times
86 'dumpuser' => '"' . (getpwuid($<))[0] . '"', # current username
88 # These dirs are under CONFIG_DIR just for ease of destruction.
89 # This is not a recommended layout!
90 'infofile' => "\"$infofile\"",
91 'logdir' => "\"$logdir\"",
92 'indexdir' => "\"$indexdir\"",
95 # (this is actually added while writing the config file, if not
96 # overridden by the caller)
97 # 'tapetype' => '"TEST-TAPE"',
100 # global client config
102 'amandates' => "\"$Installcheck::TMP/TESTCONF/amandates\"",
103 'gnutar_list_dir' => "\"$Installcheck::TMP/TESTCONF/gnutar_listdir\"",
106 # config-specific client config
107 'client_config_params' => [
110 # Subsections are stored as a hashref of arrayrefs, keyed by
116 'holdingdisks' => [ ],
117 'application' => [ ],
125 bless($self, $class);
127 $self->add_tapetype('TEST-TAPE', [
128 'length' => '50 mbytes',
129 'filemark' => '4 kbytes'
134 =item C<add_param($param, $value)>
136 Add the given parameter to the configuration file. Note that strings which
137 should be quoted in the configuration file itself must be double-quoted here,
140 $testconf->add_param('org' => '"MyOrganization"');
146 my ($param, $value) = @_;
148 push @{$self->{'params'}}, $param, $value;
151 =item C<add_client_param($param, $value)>, C<add_client_config_param($param, $value)>
153 Add the given parameter to the client configuration file, as C<add_param> does
154 for the server configuration file. C<add_client_param> addresses the global
155 client configuration file, while C<add_client_config_param> inserts parmeters
156 into C<TESTCONF/amanda-client.conf>.
158 $testconf->add_client_param('auth' => '"krb2"');
159 $testconf->add_client_config_param('client_username' => '"freddy"');
163 sub add_client_param {
165 my ($param, $value) = @_;
167 push @{$self->{'client_params'}}, $param, $value;
170 sub add_client_config_param {
172 my ($param, $value) = @_;
174 push @{$self->{'client_config_params'}}, $param, $value;
177 =item C<remove_param($param)>
179 Remove the given parameter from the config file.
189 while (@{$self->{'params'}}) {
190 my ($p, $v) = (shift @{$self->{'params'}}, shift @{$self->{'params'}});
191 next if $p eq $param;
192 push @new_params, $p, $v;
195 $self->{'params'} = \@new_params;
198 =item C<add_tapetype($name, $values_arrayref)>
199 =item C<add_dumptype($name, $values_arrayref)>
200 =item C<add_holdingdisk($name, $values_arrayref)>
201 =item C<add_holdingdisk_def($name, $values_arrayref)>
202 =item C<add_interface($name, $values_arrayref)>
203 =item C<add_application($name, $values_arrayref)>
204 =item C<add_script($name, $values_arrayref)>
205 =item C<add_device($name, $values_arrayref)>
206 =item C<add_changer($name, $values_arrayref)>
207 =item C<add_interactivity($name, $values_arrayref)>
208 =item C<add_taperscan($name, $values_arrayref)>
210 Add the given subsection to the configuration file, including all values in the
211 arrayref. The values should be specified as alternating key/value pairs.
212 Since holdingdisk definitions usually don't have a "define" keyword,
213 C<add_holdingdisk> does not add one, but C<add_holdingdisk_def> does.
219 my ($subsec, $name, $use_define, $values) = @_;
221 # first delete any existing subsections with that name
222 @{$self->{$subsec}} = grep { $_->[0] ne $name } @{$self->{$subsec}};
224 # and now push the new subsection definition on the end
225 push @{$self->{$subsec}}, [$name, $use_define, $values];
230 my ($name, $values) = @_;
231 $self->_add_subsec("tapetypes", $name, 1, $values);
236 my ($name, $values) = @_;
237 $self->_add_subsec("dumptypes", $name, 1, $values);
240 # by default, holdingdisks don't have the "define" keyword
241 sub add_holdingdisk {
243 my ($name, $values) = @_;
244 $self->_add_subsec("holdingdisks", $name, 0, $values);
247 # add a holdingdisk definition only (use "define" keyword)
248 sub add_holdingdisk_def {
250 my ($name, $values) = @_;
251 $self->_add_subsec("holdingdisks", $name, 1, $values);
256 my ($name, $values) = @_;
257 $self->_add_subsec("interfaces", $name, 1, $values);
260 sub add_application {
262 my ($name, $values) = @_;
263 $self->_add_subsec("application", $name, 1, $values);
268 my ($name, $values) = @_;
269 $self->_add_subsec("script", $name, 1, $values);
274 my ($name, $values) = @_;
275 $self->_add_subsec("devices", $name, 1, $values);
280 my ($name, $values) = @_;
281 $self->_add_subsec("changers", $name, 1, $values);
284 sub add_interactivity {
286 my ($name, $values) = @_;
287 $self->_add_subsec("interactivities", $name, 1, $values);
292 my ($name, $values) = @_;
293 $self->_add_subsec("taperscans", $name, 1, $values);
296 =item C<add_text($text)>
298 Add arbitrary text to the config file.
305 $self->{'text'} .= $text;
308 =item C<add_dle($line)>
310 Add a disklist entry; C<$line> is inserted verbatim into the disklist.
317 push @{$self->{'dles'}}, $line;
322 Write out the accumulated configuration file, along with any other
323 files necessary to run Amanda.
332 my $testconf_dir = "$CONFIG_DIR/TESTCONF";
333 mkpath($testconf_dir);
335 # set up curinfo dir, etc.
336 mkpath($self->{'infofile'}) or die("Could not create infofile directory");
337 mkpath($self->{'logdir'}) or die("Could not create logdir directory");
338 mkpath($self->{'indexdir'}) or die("Could not create indexdir directory");
339 my $amandates = $Installcheck::TMP . "/TESTCONF/amandates";
340 my $gnutar_listdir = $Installcheck::TMP . "/TESTCONF/gnutar_listdir";
341 if (! -d $gnutar_listdir) {
342 mkpath($gnutar_listdir)
343 or die("Could not create '$gnutar_listdir'");
346 $self->_write_tapelist("$testconf_dir/tapelist");
347 $self->_write_disklist("$testconf_dir/disklist");
348 $self->_write_amanda_conf("$testconf_dir/amanda.conf");
349 $self->_write_amandates($amandates);
350 $self->_write_amanda_client_conf("$CONFIG_DIR/amanda-client.conf");
351 $self->_write_amanda_client_config_conf("$testconf_dir/amanda-client.conf");
354 sub _write_tapelist {
358 # create an empty tapelist
359 open(my $tapelist, ">", $filename);
363 sub _write_disklist {
367 # don't bother writing a disklist if there are no dle's
368 return unless $self->{'dles'};
370 open(my $disklist, ">", $filename);
372 for my $dle_line (@{$self->{'dles'}}) {
373 print $disklist "$dle_line\n";
379 sub _write_amanda_conf {
383 open my $amanda_conf, ">", $filename
384 or croak("Could not open '$filename'");
386 # write key/value pairs
387 my @params = @{$self->{'params'}};
388 my $saw_tapetype = 0;
391 $param = shift @params;
392 $value = shift @params;
393 if ($param eq 'taperscan') {
397 print $amanda_conf "$param $value\n";
398 $saw_tapetype = 1 if ($param eq "tapetype");
401 # tapetype is special-cased: if the user has not specified a tapetype, use "TEST-TAPE".
402 if (!$saw_tapetype) {
403 print $amanda_conf "tapetype \"TEST-TAPE\"\n";
406 # write out subsections
407 $self->_write_amanda_conf_subsection($amanda_conf, "tapetype", $self->{"tapetypes"});
408 $self->_write_amanda_conf_subsection($amanda_conf, "application", $self->{"application"});
409 $self->_write_amanda_conf_subsection($amanda_conf, "script", $self->{"script"});
410 $self->_write_amanda_conf_subsection($amanda_conf, "dumptype", $self->{"dumptypes"});
411 $self->_write_amanda_conf_subsection($amanda_conf, "interface", $self->{"interfaces"});
412 $self->_write_amanda_conf_subsection($amanda_conf, "holdingdisk", $self->{"holdingdisks"});
413 $self->_write_amanda_conf_subsection($amanda_conf, "device", $self->{"devices"});
414 $self->_write_amanda_conf_subsection($amanda_conf, "changer", $self->{"changers"});
415 $self->_write_amanda_conf_subsection($amanda_conf, "interactivity", $self->{"interactivities"});
416 $self->_write_amanda_conf_subsection($amanda_conf, "taperscan", $self->{"taperscans"});
417 print $amanda_conf "\n", $self->{'text'}, "\n";
418 print $amanda_conf "taperscan $taperscan\n" if $taperscan;
423 sub _write_amanda_conf_subsection {
425 my ($amanda_conf, $subsec_type, $subsec_ref) = @_;
427 for my $subsec_info (@$subsec_ref) {
428 my ($subsec_name, $use_define, $values) = @$subsec_info;
430 my $define = $use_define? "define " : "";
431 print $amanda_conf "\n$define$subsec_type $subsec_name {\n";
433 my @values = @$values; # make a copy
435 $param = shift @values;
436 $value = shift @values;
437 if ($param eq "inherit") {
438 print $amanda_conf "$value\n";
439 } elsif (defined $value) {
440 print $amanda_conf "$param $value\n";
442 print $amanda_conf "$param\n";
445 print $amanda_conf "}\n";
449 sub _write_amandates {
453 # make sure the containing directory exists
454 mkpath($filename =~ /(^.*)\/amandates/);
456 # truncate the file to eliminate any interference from previous runs
457 open(my $amandates, ">", $filename) or die("Could not write to '$filename'");
461 sub _write_amanda_client_conf {
463 my ($filename, $amandates, $gnutar_listdir) = @_;
465 # just an empty file for now
466 open(my $amanda_client_conf, ">", $filename)
467 or croak("Could not write to '$filename'");
469 # write key/value pairs
470 my @params = @{$self->{'client_params'}};
472 $param = shift @params;
473 $value = shift @params;
474 print $amanda_client_conf "$param $value\n";
477 close($amanda_client_conf);
480 sub _write_amanda_client_config_conf {
482 my ($filename, $amandates, $gnutar_listdir) = @_;
484 # just an empty file for now
485 open(my $amanda_client_conf, ">", $filename)
486 or croak("Could not write to '$filename'");
488 # write key/value pairs
489 my @params = @{$self->{'client_config_params'}};
491 $param = shift @params;
492 $value = shift @params;
493 print $amanda_client_conf "$param $value\n";
496 close($amanda_client_conf);
499 =item C<cleanup()> (callable as a package method too)
501 Clean up by deleting the configuration directory.
506 my $testconf_dir = "$CONFIG_DIR/TESTCONF";
507 if (-e $testconf_dir) {
508 rmtree($testconf_dir) or die("Could not remove '$testconf_dir'");