2 # Copyright (c) 2008,2009 Zmanda, Inc. All Rights Reserved.
4 # This program is free software; you can redistribute it and/or modify it
5 # under the terms of the GNU General Public License version 2 as published
6 # by the Free Software Foundation.
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
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
17 # Contact information: Zmanda Inc, 465 S. Mathilda Ave., Suite 300
18 # Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
20 package Installcheck::Config;
23 use Amanda::Constants;
29 Installcheck::Config - set up amanda configurations for installcheck testing
33 use Installcheck::Config;
35 my $testconf = Installcheck::Config->new();
36 $testconf->add_param("runtapes", "5");
37 $testconf->add_tapetype("DUCKTAPE", [
38 length => "10G", filemark => "4096k",
43 The resulting configuration is always named "TESTCONF". The basic
44 configuration contains only a few parameters that are necessary
45 just to run Amanda applications in the test environment. It also
46 contains a tapetype, C<TEST-TAPE>. To change tapetype parameters,
47 call C<< $cf->add_tapetype >> with a new definition of C<TEST-TAPE>.
49 Note that it's quite possible to produce an invalid configuration with this
50 package (and, in fact, some of the tests do just that).
54 Using this module I<will> destroy any existing configuration named
55 TESTDIR. I<Please> do not use this on a production machine!
63 Create a new configuration object
70 # An instance is a blessed hash containing parameters. Start with
71 # some defaults to make sure things run.
72 my $infofile = "$CONFIG_DIR/TESTCONF/curinfo";
73 my $logdir = "$CONFIG_DIR/TESTCONF/log";
74 my $indexdir = "$CONFIG_DIR/TESTCONF/index";
75 my $org = "DailySet1";
78 'infofile' => $infofile,
80 'indexdir' => $indexdir,
82 # Global params are stored as an arrayref, so that the same declaration
83 # can appear multiple times
85 'dumpuser' => '"' . (getpwuid($<))[0] . '"', # current username
87 # These dirs are under CONFIG_DIR just for ease of destruction.
88 # This is not a recommended layout!
89 'infofile' => "\"$infofile\"",
90 'logdir' => "\"$logdir\"",
91 'indexdir' => "\"$indexdir\"",
94 # (this is actually added while writing the config file, if not
95 # overridden by the caller)
96 # 'tapetype' => '"TEST-TAPE"',
99 # global client config
101 'amandates' => "\"$Installcheck::TMP/TESTCONF/amandates\"",
102 'gnutar_list_dir' => "\"$Installcheck::TMP/TESTCONF/gnutar_listdir\"",
105 # config-specific client config
106 'client_config_params' => [
109 # Subsections are stored as a hashref of arrayrefs, keyed by
115 'holdingdisks' => [ ],
116 'application' => [ ],
124 bless($self, $class);
126 $self->add_tapetype('TEST-TAPE', [
127 'length' => '50 mbytes',
128 'filemark' => '4 kbytes'
133 =item C<add_param($param, $value)>
135 Add the given parameter to the configuration file. Note that strings which
136 should be quoted in the configuration file itself must be double-quoted here,
139 $testconf->add_param('org' => '"MyOrganization"');
145 my ($param, $value) = @_;
147 push @{$self->{'params'}}, $param, $value;
150 =item C<add_client_param($param, $value)>, C<add_client_config_param($param, $value)>
152 Add the given parameter to the client configuration file, as C<add_param> does
153 for the server configuration file. C<add_client_param> addresses the global
154 client configuration file, while C<add_client_config_param> inserts parmeters
155 into C<TESTCONF/amanda-client.conf>.
157 $testconf->add_client_param('auth' => '"krb2"');
158 $testconf->add_client_config_param('client_username' => '"freddy"');
162 sub add_client_param {
164 my ($param, $value) = @_;
166 push @{$self->{'client_params'}}, $param, $value;
169 sub add_client_config_param {
171 my ($param, $value) = @_;
173 push @{$self->{'client_config_params'}}, $param, $value;
176 =item C<remove_param($param)>
178 Remove the given parameter from the config file.
188 while (@{$self->{'params'}}) {
189 my ($p, $v) = (shift @{$self->{'params'}}, shift @{$self->{'params'}});
190 next if $p eq $param;
191 push @new_params, $p, $v;
194 $self->{'params'} = \@new_params;
197 =item C<add_tapetype($name, $values_arrayref)>
198 =item C<add_dumptype($name, $values_arrayref)>
199 =item C<add_holdingdisk($name, $values_arrayref)>
200 =item C<add_holdingdisk_def($name, $values_arrayref)>
201 =item C<add_interface($name, $values_arrayref)>
202 =item C<add_application($name, $values_arrayref)>
203 =item C<add_script($name, $values_arrayref)>
204 =item C<add_device($name, $values_arrayref)>
205 =item C<add_changer($name, $values_arrayref)>
206 =item C<add_interactivity($name, $values_arrayref)>
207 =item C<add_taperscan($name, $values_arrayref)>
209 Add the given subsection to the configuration file, including all values in the
210 arrayref. The values should be specified as alternating key/value pairs.
211 Since holdingdisk definitions usually don't have a "define" keyword,
212 C<add_holdingdisk> does not add one, but C<add_holdingdisk_def> does.
218 my ($subsec, $name, $use_define, $values) = @_;
220 # first delete any existing subsections with that name
221 @{$self->{$subsec}} = grep { $_->[0] ne $name } @{$self->{$subsec}};
223 # and now push the new subsection definition on the end
224 push @{$self->{$subsec}}, [$name, $use_define, $values];
229 my ($name, $values) = @_;
230 $self->_add_subsec("tapetypes", $name, 1, $values);
235 my ($name, $values) = @_;
236 $self->_add_subsec("dumptypes", $name, 1, $values);
239 # by default, holdingdisks don't have the "define" keyword
240 sub add_holdingdisk {
242 my ($name, $values) = @_;
243 $self->_add_subsec("holdingdisks", $name, 0, $values);
246 # add a holdingdisk definition only (use "define" keyword)
247 sub add_holdingdisk_def {
249 my ($name, $values) = @_;
250 $self->_add_subsec("holdingdisks", $name, 1, $values);
255 my ($name, $values) = @_;
256 $self->_add_subsec("interfaces", $name, 1, $values);
259 sub add_application {
261 my ($name, $values) = @_;
262 $self->_add_subsec("application", $name, 1, $values);
267 my ($name, $values) = @_;
268 $self->_add_subsec("script", $name, 1, $values);
273 my ($name, $values) = @_;
274 $self->_add_subsec("devices", $name, 1, $values);
279 my ($name, $values) = @_;
280 $self->_add_subsec("changers", $name, 1, $values);
283 sub add_interactivity {
285 my ($name, $values) = @_;
286 $self->_add_subsec("interactivities", $name, 1, $values);
291 my ($name, $values) = @_;
292 $self->_add_subsec("taperscans", $name, 1, $values);
295 =item C<add_text($text)>
297 Add arbitrary text to the config file.
304 $self->{'text'} .= $text;
307 =item C<add_dle($line)>
309 Add a disklist entry; C<$line> is inserted verbatim into the disklist.
316 push @{$self->{'dles'}}, $line;
321 Write out the accumulated configuration file, along with any other
322 files necessary to run Amanda.
331 my $testconf_dir = "$CONFIG_DIR/TESTCONF";
332 mkpath($testconf_dir);
334 # set up curinfo dir, etc.
335 mkpath($self->{'infofile'}) or die("Could not create infofile directory");
336 mkpath($self->{'logdir'}) or die("Could not create logdir directory");
337 mkpath($self->{'indexdir'}) or die("Could not create indexdir directory");
338 my $amandates = $Installcheck::TMP . "/TESTCONF/amandates";
339 my $gnutar_listdir = $Installcheck::TMP . "/TESTCONF/gnutar_listdir";
340 if (! -d $gnutar_listdir) {
341 mkpath($gnutar_listdir)
342 or die("Could not create '$gnutar_listdir'");
345 $self->_write_tapelist("$testconf_dir/tapelist");
346 $self->_write_disklist("$testconf_dir/disklist");
347 $self->_write_amanda_conf("$testconf_dir/amanda.conf");
348 $self->_write_amandates($amandates);
349 $self->_write_amanda_client_conf("$CONFIG_DIR/amanda-client.conf");
350 $self->_write_amanda_client_config_conf("$testconf_dir/amanda-client.conf");
353 sub _write_tapelist {
357 # create an empty tapelist
358 open(my $tapelist, ">", $filename);
362 sub _write_disklist {
366 # don't bother writing a disklist if there are no dle's
367 return unless $self->{'dles'};
369 open(my $disklist, ">", $filename);
371 for my $dle_line (@{$self->{'dles'}}) {
372 print $disklist "$dle_line\n";
378 sub _write_amanda_conf {
382 open my $amanda_conf, ">", $filename
383 or croak("Could not open '$filename'");
385 # write key/value pairs
386 my @params = @{$self->{'params'}};
387 my $saw_tapetype = 0;
390 $param = shift @params;
391 $value = shift @params;
392 if ($param eq 'taperscan') {
396 print $amanda_conf "$param $value\n";
397 $saw_tapetype = 1 if ($param eq "tapetype");
400 # tapetype is special-cased: if the user has not specified a tapetype, use "TEST-TAPE".
401 if (!$saw_tapetype) {
402 print $amanda_conf "tapetype \"TEST-TAPE\"\n";
405 # write out subsections
406 $self->_write_amanda_conf_subsection($amanda_conf, "tapetype", $self->{"tapetypes"});
407 $self->_write_amanda_conf_subsection($amanda_conf, "application", $self->{"application"});
408 $self->_write_amanda_conf_subsection($amanda_conf, "script", $self->{"script"});
409 $self->_write_amanda_conf_subsection($amanda_conf, "dumptype", $self->{"dumptypes"});
410 $self->_write_amanda_conf_subsection($amanda_conf, "interface", $self->{"interfaces"});
411 $self->_write_amanda_conf_subsection($amanda_conf, "holdingdisk", $self->{"holdingdisks"});
412 $self->_write_amanda_conf_subsection($amanda_conf, "device", $self->{"devices"});
413 $self->_write_amanda_conf_subsection($amanda_conf, "changer", $self->{"changers"});
414 $self->_write_amanda_conf_subsection($amanda_conf, "interactivity", $self->{"interactivities"});
415 $self->_write_amanda_conf_subsection($amanda_conf, "taperscan", $self->{"taperscans"});
416 print $amanda_conf "\n", $self->{'text'}, "\n";
417 print $amanda_conf "taperscan $taperscan\n" if $taperscan;
422 sub _write_amanda_conf_subsection {
424 my ($amanda_conf, $subsec_type, $subsec_ref) = @_;
426 for my $subsec_info (@$subsec_ref) {
427 my ($subsec_name, $use_define, $values) = @$subsec_info;
429 my $define = $use_define? "define " : "";
430 print $amanda_conf "\n$define$subsec_type $subsec_name {\n";
432 my @values = @$values; # make a copy
434 $param = shift @values;
435 $value = shift @values;
436 if ($param eq "inherit") {
437 print $amanda_conf "$value\n";
439 print $amanda_conf "$param $value\n";
442 print $amanda_conf "}\n";
446 sub _write_amandates {
450 # make sure the containing directory exists
451 mkpath($filename =~ /(^.*)\/amandates/);
453 # truncate the file to eliminate any interference from previous runs
454 open(my $amandates, ">", $filename) or die("Could not write to '$filename'");
458 sub _write_amanda_client_conf {
460 my ($filename, $amandates, $gnutar_listdir) = @_;
462 # just an empty file for now
463 open(my $amanda_client_conf, ">", $filename)
464 or croak("Could not write to '$filename'");
466 # write key/value pairs
467 my @params = @{$self->{'client_params'}};
469 $param = shift @params;
470 $value = shift @params;
471 print $amanda_client_conf "$param $value\n";
474 close($amanda_client_conf);
477 sub _write_amanda_client_config_conf {
479 my ($filename, $amandates, $gnutar_listdir) = @_;
481 # just an empty file for now
482 open(my $amanda_client_conf, ">", $filename)
483 or croak("Could not write to '$filename'");
485 # write key/value pairs
486 my @params = @{$self->{'client_config_params'}};
488 $param = shift @params;
489 $value = shift @params;
490 print $amanda_client_conf "$param $value\n";
493 close($amanda_client_conf);
496 =item C<cleanup()> (callable as a package method too)
498 Clean up by deleting the configuration directory.
503 my $testconf_dir = "$CONFIG_DIR/TESTCONF";
504 if (-e $testconf_dir) {
505 rmtree($testconf_dir) or die("Could not remove '$testconf_dir'");