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)>
207 Add the given subsection to the configuration file, including all values in the
208 arrayref. The values should be specified as alternating key/value pairs.
209 Since holdingdisk definitions usually don't have a "define" keyword,
210 C<add_holdingdisk> does not add one, but C<add_holdingdisk_def> does.
216 my ($subsec, $name, $use_define, $values) = @_;
218 # first delete any existing subsections with that name
219 @{$self->{$subsec}} = grep { $_->[0] ne $name } @{$self->{$subsec}};
221 # and now push the new subsection definition on the end
222 push @{$self->{$subsec}}, [$name, $use_define, $values];
227 my ($name, $values) = @_;
228 $self->_add_subsec("tapetypes", $name, 1, $values);
233 my ($name, $values) = @_;
234 $self->_add_subsec("dumptypes", $name, 1, $values);
237 # by default, holdingdisks don't have the "define" keyword
238 sub add_holdingdisk {
240 my ($name, $values) = @_;
241 $self->_add_subsec("holdingdisks", $name, 0, $values);
244 # add a holdingdisk definition only (use "define" keyword)
245 sub add_holdingdisk_def {
247 my ($name, $values) = @_;
248 $self->_add_subsec("holdingdisks", $name, 1, $values);
253 my ($name, $values) = @_;
254 $self->_add_subsec("interfaces", $name, 1, $values);
257 sub add_application {
259 my ($name, $values) = @_;
260 $self->_add_subsec("application", $name, 1, $values);
265 my ($name, $values) = @_;
266 $self->_add_subsec("script", $name, 1, $values);
271 my ($name, $values) = @_;
272 $self->_add_subsec("devices", $name, 1, $values);
277 my ($name, $values) = @_;
278 $self->_add_subsec("changers", $name, 1, $values);
281 =item C<add_text($text)>
283 Add arbitrary text to the config file.
290 $self->{'text'} .= $text;
293 =item C<add_dle($line)>
295 Add a disklist entry; C<$line> is inserted verbatim into the disklist.
302 push @{$self->{'dles'}}, $line;
307 Write out the accumulated configuration file, along with any other
308 files necessary to run Amanda.
317 my $testconf_dir = "$CONFIG_DIR/TESTCONF";
318 mkpath($testconf_dir);
320 # set up curinfo dir, etc.
321 mkpath($self->{'infofile'}) or die("Could not create infofile directory");
322 mkpath($self->{'logdir'}) or die("Could not create logdir directory");
323 mkpath($self->{'indexdir'}) or die("Could not create indexdir directory");
324 my $amandates = $Installcheck::TMP . "/TESTCONF/amandates";
325 my $gnutar_listdir = $Installcheck::TMP . "/TESTCONF/gnutar_listdir";
326 if (! -d $gnutar_listdir) {
327 mkpath($gnutar_listdir)
328 or die("Could not create '$gnutar_listdir'");
331 $self->_write_tapelist("$testconf_dir/tapelist");
332 $self->_write_disklist("$testconf_dir/disklist");
333 $self->_write_amanda_conf("$testconf_dir/amanda.conf");
334 $self->_write_amandates($amandates);
335 $self->_write_amanda_client_conf("$CONFIG_DIR/amanda-client.conf");
336 $self->_write_amanda_client_config_conf("$testconf_dir/amanda-client.conf");
339 sub _write_tapelist {
343 # create an empty tapelist
344 open(my $tapelist, ">", $filename);
348 sub _write_disklist {
352 # don't bother writing a disklist if there are no dle's
353 return unless $self->{'dles'};
355 open(my $disklist, ">", $filename);
357 for my $dle_line (@{$self->{'dles'}}) {
358 print $disklist "$dle_line\n";
364 sub _write_amanda_conf {
368 open my $amanda_conf, ">", $filename
369 or croak("Could not open '$filename'");
371 # write key/value pairs
372 my @params = @{$self->{'params'}};
373 my $saw_tapetype = 0;
375 $param = shift @params;
376 $value = shift @params;
377 print $amanda_conf "$param $value\n";
378 $saw_tapetype = 1 if ($param eq "tapetype");
381 # tapetype is special-cased: if the user has not specified a tapetype, use "TEST-TAPE".
382 if (!$saw_tapetype) {
383 print $amanda_conf "tapetype \"TEST-TAPE\"\n";
386 # write out subsections
387 $self->_write_amanda_conf_subsection($amanda_conf, "tapetype", $self->{"tapetypes"});
388 $self->_write_amanda_conf_subsection($amanda_conf, "application", $self->{"application"});
389 $self->_write_amanda_conf_subsection($amanda_conf, "script", $self->{"script"});
390 $self->_write_amanda_conf_subsection($amanda_conf, "dumptype", $self->{"dumptypes"});
391 $self->_write_amanda_conf_subsection($amanda_conf, "interface", $self->{"interfaces"});
392 $self->_write_amanda_conf_subsection($amanda_conf, "holdingdisk", $self->{"holdingdisks"});
393 $self->_write_amanda_conf_subsection($amanda_conf, "device", $self->{"devices"});
394 $self->_write_amanda_conf_subsection($amanda_conf, "changer", $self->{"changers"});
395 print $amanda_conf "\n", $self->{'text'}, "\n";
400 sub _write_amanda_conf_subsection {
402 my ($amanda_conf, $subsec_type, $subsec_ref) = @_;
404 for my $subsec_info (@$subsec_ref) {
405 my ($subsec_name, $use_define, $values) = @$subsec_info;
407 my $define = $use_define? "define " : "";
408 print $amanda_conf "\n$define$subsec_type $subsec_name {\n";
410 my @values = @$values; # make a copy
412 $param = shift @values;
413 $value = shift @values;
414 if ($param eq "inherit") {
415 print $amanda_conf "$value\n";
417 print $amanda_conf "$param $value\n";
420 print $amanda_conf "}\n";
424 sub _write_amandates {
428 # make sure the containing directory exists
429 mkpath($filename =~ /(^.*)\/amandates/);
431 # truncate the file to eliminate any interference from previous runs
432 open(my $amandates, ">", $filename) or die("Could not write to '$filename'");
436 sub _write_amanda_client_conf {
438 my ($filename, $amandates, $gnutar_listdir) = @_;
440 # just an empty file for now
441 open(my $amanda_client_conf, ">", $filename)
442 or croak("Could not write to '$filename'");
444 # write key/value pairs
445 my @params = @{$self->{'client_params'}};
447 $param = shift @params;
448 $value = shift @params;
449 print $amanda_client_conf "$param $value\n";
452 close($amanda_client_conf);
455 sub _write_amanda_client_config_conf {
457 my ($filename, $amandates, $gnutar_listdir) = @_;
459 # just an empty file for now
460 open(my $amanda_client_conf, ">", $filename)
461 or croak("Could not write to '$filename'");
463 # write key/value pairs
464 my @params = @{$self->{'client_config_params'}};
466 $param = shift @params;
467 $value = shift @params;
468 print $amanda_client_conf "$param $value\n";
471 close($amanda_client_conf);
474 =item C<cleanup()> (callable as a package method too)
476 Clean up by deleting the configuration directory.
481 my $testconf_dir = "$CONFIG_DIR/TESTCONF";
482 if (-e $testconf_dir) {
483 rmtree($testconf_dir) or die("Could not remove '$testconf_dir'");