]> git.sur5r.net Git - bacula/bacula/blob - regress/scripts/functions.pm
regress: tweak diff.pl output
[bacula/bacula] / regress / scripts / functions.pm
1 ################################################################
2 use strict;
3
4 =head1 LICENSE
5
6    Bacula® - The Network Backup Solution
7
8    Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
9
10    The main author of Bacula is Kern Sibbald, with contributions from
11    many others, a complete list can be found in the file AUTHORS.
12
13    This program is Free Software; you can redistribute it and/or
14    modify it under the terms of version two of the GNU General Public
15    License as published by the Free Software Foundation plus additions
16    that are listed in the file LICENSE.
17
18    This program is distributed in the hope that it will be useful, but
19    WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21    General Public License for more details.
22
23    You should have received a copy of the GNU General Public License
24    along with this program; if not, write to the Free Software
25    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26    02110-1301, USA.
27
28    Bacula® is a registered trademark of Kern Sibbald.
29    The licensor of Bacula is the Free Software Foundation Europe
30    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zurich,
31    Switzerland, email:ftf@fsfeurope.org.
32
33 =cut
34
35 package scripts::functions;
36 # Export all functions needed to be used by a simple 
37 # perl -Mscripts::functions -e '' script
38 use Exporter;
39 our @ISA = qw(Exporter);
40 our @EXPORT =  qw(update_some_files create_many_files check_multiple_copies
41                   update_client $HOST $BASEPORT add_to_backup_list check_volume_size
42                   create_many_dirs cleanup start_bacula stop_bacula get_resource
43                   set_maximum_concurrent_jobs get_time add_attribute check_job_list
44                   check_min_volume_size check_max_volume_size $estat $bstat $rstat $zstat
45                   $cwd $bin $scripts $conf $rscripts $tmp $working extract_resource
46                   $db_name $db_user $db_password $src $tmpsrc);
47
48
49 use File::Copy qw/copy/;
50
51 our ($cwd, $bin, $scripts, $conf, $rscripts, $tmp, $working, $estat, $bstat, $zstat, $rstat,
52      $db_name, $db_user, $db_password, $src, $tmpsrc, $HOST, $BASEPORT);
53
54 END {
55     if ($estat || $rstat || $zstat || $bstat) {
56         exit 1;
57     }
58 }
59
60 BEGIN {
61     # start by loading the ./config file
62     my ($envar, $enval);
63     if (! -f "./config") {
64         die "Could not find ./config file\n";
65     }
66     # load the ./config file in a subshell doesn't allow to use "env" to display all variable
67     open(IN, ". ./config; env |") or die "Could not run shell: $!\n";
68     while ( my $l = <IN> ) {
69         chomp ($l);
70         ($envar,$enval) = split (/=/,$l,2);
71         $ENV{$envar} = $enval;
72     }
73     close(IN);
74     $cwd = `pwd`; 
75     chomp($cwd);
76
77     # set internal variable name and update environment variable
78     $ENV{db_name} = $db_name = $ENV{db_name} || 'regress';
79     $ENV{db_user} = $db_user = $ENV{db_user} || 'regress';
80     $ENV{db_password} = $db_password = $ENV{db_password} || '';
81
82     $ENV{bin}      = $bin      =  $ENV{bin}      || "$cwd/bin";
83     $ENV{tmp}      = $tmp      =  $ENV{tmp}      || "$cwd/tmp";
84     $ENV{src}      = $src      =  $ENV{src}      || "$cwd/src";
85     $ENV{conf}     = $conf     =  $ENV{conf}     || $bin;
86     $ENV{scripts}  = $scripts  =  $ENV{scripts}  || $bin;
87     $ENV{tmpsrc}   = $tmpsrc   =  $ENV{tmpsrc}   || "$cwd/tmp/build";
88     $ENV{working}  = $working  =  $ENV{working}  || "$cwd/working";    
89     $ENV{rscripts} = $rscripts =  $ENV{rscripts} || "$cwd/scripts";
90     $ENV{HOST}     = $HOST     =  $ENV{HOST}     || "localhost";
91     $ENV{BASEPORT} = $BASEPORT =  $ENV{BASEPORT} || "8101";
92
93     $estat = $rstat = $bstat = $zstat = 0;
94 }
95
96 sub cleanup
97 {
98     system("$rscripts/cleanup");
99     return $? == 0;
100 }
101
102 sub start_bacula
103 {
104     my $ret;
105     $ENV{LANG}='C';
106     system("$bin/bacula start");
107     $ret = $? == 0;
108     open(FP, ">$tmp/bcmd");
109     print FP "sql\ntruncate client_group;\ntruncate client_group_member;\nupdate Media set LocationId=0;\ntruncate location;\n\n";
110     close(FP);
111     system("cat $tmp/bcmd | $bin/bconsole >/dev/null");
112     return $ret;
113 }
114
115 sub stop_bacula
116 {
117     $ENV{LANG}='C';
118     system("$bin/bacula stop");
119     return $? == 0;
120 }
121
122 sub get_resource
123 {
124     my ($file, $type, $name) = @_;
125     my $ret;
126     open(FP, $file) or die "Can't open $file";
127     my $content = join("", <FP>);
128     
129     if ($content =~ m/(^$type {[^}]+?Name\s*=\s*"?$name"?[^}]+?^})/ms) {
130         $ret = $1;
131     }
132
133     close(FP);
134     return $ret;
135 }
136
137 sub extract_resource
138 {
139     my $ret = get_resource(@_);
140     if ($ret) {
141         print $ret, "\n";
142     }
143 }
144
145 sub check_min_volume_size
146 {
147     my ($size, @vol) = @_;
148     my $ret=0;
149
150     foreach my $v (@vol) {
151         if (! -f "$tmp/$v") {
152             print "ERR: $tmp/$v not accessible\n";
153             $ret++;
154             next;
155         }
156         if (-s "$tmp/$v" < $size) {
157             print "ERR: $tmp/$v too small\n";
158             $ret++;
159         }
160     }
161     $estat+=$ret;
162     return $ret;
163 }
164
165 sub check_max_volume_size
166 {
167     my ($size, @vol) = @_;
168     my $ret=0;
169
170     foreach my $v (@vol) {
171         if (! -f "$tmp/$v") {
172             print "ERR: $tmp/$v not accessible\n";
173             $ret++;
174             next;
175         }
176         if (-s "$tmp/$v" > $size) {
177             print "ERR: $tmp/$v too big\n";
178             $ret++;
179         }
180     }
181     $estat+=$ret;
182     return $ret;
183 }
184
185 sub add_to_backup_list
186 {
187     open(FP, ">>$tmp/file-list") or die "Can't open $tmp/file-list for update $!";
188     print FP join("\n", @_);
189     close(FP);
190 }
191
192 # update client definition for the current test
193 # it permits to test remote client
194 sub update_client
195 {
196     my ($new_passwd, $new_address, $new_port) = @_;
197     my $in_client=0;
198
199     open(FP, "$conf/bacula-dir.conf") or die "can't open source $!";
200     open(NEW, ">$tmp/bacula-dir.conf.$$") or die "can't open dest $!";
201     while (my $l = <FP>) {
202         if (!$in_client && $l =~ /^Client {/) {
203             $in_client=1;
204         }
205         
206         if ($in_client && $l =~ /Address/i) {
207             $l = "Address = $new_address\n";
208         }
209
210         if ($in_client && $l =~ /FDPort/i) {
211             $l = "FDPort = $new_port\n";
212         }
213
214         if ($in_client && $l =~ /Password/i) {
215             $l = "Password = \"$new_passwd\"\n";
216         }
217
218         if ($in_client && $l =~ /^}/) {
219             $in_client=0;
220         }
221         print NEW $l;
222     }
223     close(FP);
224     close(NEW);
225     my $ret = copy("$tmp/bacula-dir.conf.$$", "$conf/bacula-dir.conf");
226     unlink("$tmp/bacula-dir.conf.$$");
227     return $ret;
228 }
229
230 # open a directory and update all files
231 sub update_some_files
232 {
233     my ($dest)=@_;
234     my $t=rand();
235     my $f;
236     my $nb=0;
237     print "Update files in $dest\n";
238     opendir(DIR, $dest) || die "$!";
239     map {
240         $f = "$dest/$_";
241         if (-f $f) {
242             open(FP, ">$f") or die "$f $!";
243             print FP "$t update $f\n";
244             close(FP);
245             $nb++;
246         }
247     } readdir(DIR);
248     closedir DIR;
249     print "$nb files updated\n";
250 }
251
252 # create big number of files in a given directory
253 # Inputs: dest  destination directory
254 #         nb    number of file to create
255 # Example:
256 # perl -Mscripts::functions -e 'create_many_files("$cwd/files", 100000)'
257 sub create_many_files
258 {
259     my ($dest, $nb) = @_;
260     my $base;
261     my $dir=$dest;
262     $nb = $nb || 750000;
263     mkdir $dest;
264     $base = chr($nb % 26 + 65); # We use a base directory A-Z
265
266     # already done
267     if (-f "$dest/$base/a${base}a${nb}aaa${base}") {
268         print "Files already created\n";
269         return;
270     }
271
272     # auto flush stdout for dots
273     $| = 1;
274     print "Create $nb files into $dest\n";
275     for(my $i=0; $i < 26; $i++) {
276         $base = chr($i + 65);
277         mkdir("$dest/$base") if (! -d "$dest/$base");
278     }
279     for(my $i=0; $i<=$nb; $i++) {
280         $base = chr($i % 26 + 65);
281         open(FP, ">$dest/$base/a${base}a${i}aaa$base") or die "$dest/$base $!";
282         print FP "$i\n";
283         close(FP);
284         
285         open(FP, ">$dir/b${base}a${i}csq$base") or die "$dir $!";
286         print FP "$base $i\n";
287         close(FP);
288         
289         if (!($i % 100)) {
290             $dir = "$dest/$base/$base$i$base";
291             mkdir $dir;
292         }
293         print "." if (!($i % 10000));
294     }
295     print "\n";
296 }
297
298 # create big number of dirs in a given directory
299 # Inputs: dest  destination directory
300 #         nb    number of dirs to create
301 # Example:
302 # perl -Mscripts::functions -e 'create_many_dirs("$cwd/files", 100000)'
303 sub create_many_dirs
304 {
305     my ($dest, $nb) = @_;
306     my ($base, $base2);
307     my $dir=$dest;
308     $nb = $nb || 750000;
309     mkdir $dest;
310     $base = chr($nb % 26 + 65); # We use a base directory A-Z
311     $base2 = chr(($nb+10) % 26 + 65);
312     # already done
313     if (-d "$dest/$base/$base2/$base/a${base}a${nb}aaa${base}") {
314         print "Files already created\n";
315         return;
316     }
317
318     # auto flush stdout for dots
319     $| = 1;
320     print "Create $nb dirs into $dest\n";
321     for(my $i=0; $i < 26; $i++) {
322         $base = chr($i + 65);
323         $base2 = chr(($i+10) % 26 + 65);
324         mkdir("$dest/$base");
325         mkdir("$dest/$base/$base2");
326         mkdir("$dest/$base/$base2/$base$base2");
327         mkdir("$dest/$base/$base2/$base$base2/$base$base2");
328         mkdir("$dest/$base/$base2/$base$base2/$base$base2/$base2$base");
329     }
330     for(my $i=0; $i<=$nb; $i++) {
331         $base = chr($i % 26 + 65);
332         $base2 = chr(($i+10) % 26 + 65);
333         mkdir("$dest/$base/$base2/$base$base2/$base$base2/$base2$base/a${base}a${i}aaa$base");  
334         print "." if (!($i % 10000));
335     }
336     print "\n";
337 }
338
339 sub check_encoding
340 {
341     if (grep {/Wanted SQL_ASCII, got UTF8/} 
342         `${bin}/bacula-dir -d50 -t -c ${conf}/bacula-dir.conf 2>&1`)
343     {
344         print "Found database encoding problem, please modify the ",
345               "database encoding (SQL_ASCII)\n";
346         exit 1;
347     }
348 }
349
350 # You can change the maximum concurrent jobs for any config file
351 # If specified, you can change only one Resource or one type of
352 # resource at the time (optional)
353 #  set_maximum_concurrent_jobs('$conf/bacula-dir.conf', 100);
354 #  set_maximum_concurrent_jobs('$conf/bacula-dir.conf', 100, 'Director');
355 #  set_maximum_concurrent_jobs('$conf/bacula-dir.conf', 100, 'Device', 'Drive-0');
356 sub set_maximum_concurrent_jobs
357 {
358     my ($file, $nb, $obj, $name) = @_;
359
360     die "Can't get new maximumconcurrentjobs" 
361         unless ($nb);
362
363     add_attribute($file, "Maximum Concurrent Jobs", $nb, $obj, $name);
364 }
365
366
367 # You can add option to a resource
368 #  add_attribute('$conf/bacula-dir.conf', 'FDTimeout', 1600, 'Director');
369 #  add_attribute('$conf/bacula-dir.conf', 'FDTimeout', 1600, 'Storage', 'FileStorage');
370 sub add_attribute
371 {
372     my ($file, $attr, $value, $obj, $name) = @_;
373     my ($cur_obj, $cur_name, $done);
374
375     open(FP, ">$tmp/1.$$") or die "Can't write to $tmp/1.$$";
376     open(SRC, $file) or die "Can't open $file";
377     while (my $l = <SRC>)
378     {
379         if ($l =~ /^#/) {
380             print FP $l;
381             next;
382         }
383
384         if ($l =~ /^(\w+) {/) {
385             $cur_obj = $1;
386             $done=0;
387         }
388
389         if ($l =~ /\Q$attr\E/i) {
390             if (!$obj || $cur_obj eq $obj) {
391                 if (!$name || $cur_name eq $name) {
392                     $l =~ s/\Q$attr\E\s*=\s*.+/$attr = $value/ig;
393                     $done=1
394                 }
395             }
396         }
397
398         if ($l =~ /Name\s*=\s*"?([\w\d\.-]+)"?/i) {
399             $cur_name = $1;
400         }
401
402         if ($l =~ /^}/) {
403             if (!$done) {
404                 if ($cur_obj eq $obj) {
405                     if (!$name || $cur_name eq $name) {
406                         $l = "  $attr = $value\n$l";
407                     }
408                 }
409             }
410             $cur_name = $cur_obj = undef;
411         }
412         print FP $l;
413     }
414     close(SRC);
415     close(FP);
416     copy("$tmp/1.$$", $file) or die "Can't copy $tmp/1.$$ to $file";
417 }
418
419 # This test the list jobs output to check differences
420 # Input: read stream from stdin or with file list argument
421 #        check if all argument are not present in the second
422 #        list jobs output
423 # Output: exit(1) if something goes wrong and print error
424 sub check_job_list
425 {
426     my $f = shift;
427     my %to_check = map { $_ => 1} @_;
428     my %seen;
429     my $in_list_jobs=0;
430     my $nb_list_job=0;
431     my $nb = scalar(@_);
432     open(FP, $f) or die "Can't open $f $!";
433     while (my $l = <FP>)          # read all files to check
434     {
435         if ($l =~ /list jobs/) {
436             $in_list_jobs=1;
437             $nb_list_job++;
438             
439             if ($nb_list_job == 2) {
440                 foreach my $jobid (keys %to_check) {
441                     if (!$seen{$jobid}) {
442                         print "ERROR: in $f, can't find $jobid in first 'list jobs'\n";
443                         exit 1;
444                     }
445                 }
446             }
447             next;
448         }
449         if ($nb_list_job == 0) {
450             next;
451         }
452         if ($l =~ /Pruned (\d+) Job for client/) {
453             if ($1 != $nb) {
454                 print "ERROR: in $f, Prune command returns $1 jobs, want $nb\n";
455                 exit 1;
456             }
457         }
458
459         if ($l =~ /No Jobs found to prune/) {
460            if ($nb != 0) {
461                 print "ERROR: in $f, Prune command returns 0 job, want $nb\n";
462                 exit 1;
463             }            
464         }
465
466         # list jobs ouput:
467         # | 1 | NightlySave | 2010-06-16 22:43:05 | B | F | 27 | 4173577 | T |
468         if ($l =~ /^\|\s+(\d+)/) {
469             if ($nb_list_job == 1) {
470                 $seen{$1}=1;
471             } else {
472                 delete $seen{$1};
473             }
474         }
475     }
476     close(FP);
477     foreach my $jobid (keys %to_check) {
478         if (!$seen{$jobid}) {
479             print "ERROR: in $f, $jobid in still present in the 2nd 'list jobs'\n";
480             exit 1;
481         }
482     }
483     exit 0;
484 }
485
486 # This test ensure that 'list copies' displays only each copy one time
487 #
488 # Input: read stream from stdin or with file list argument
489 #        check the number of copies with the ARGV[1]
490 # Output: exit(1) if something goes wrong and print error
491 sub check_multiple_copies
492 {
493     my ($nb_to_found) = @_;
494
495     my $in_list_copies=0;       # are we or not in a list copies block
496     my $nb_found=0;             # count the number of copies found
497     my $ret = 0;
498     my %seen;
499
500     while (my $l = <>)          # read all files to check
501     {
502         if ($l =~ /list copies/) {
503             $in_list_copies=1;
504             %seen = ();
505             next;
506         }
507
508         # not in a list copies anymore
509         if ($in_list_copies && $l =~ /^ /) {
510             $in_list_copies=0;
511             next;
512         }
513
514         # list copies ouput:
515         # |     3 | Backup.2009-09-28 |  9 | DiskChangerMedia |
516         if ($in_list_copies && $l =~ /^\|\s+\d+/) {
517             my (undef, $jobid, undef, $copyid, undef) = split(/\s*\|\s*/, $l);
518             if (exists $seen{$jobid}) {
519                 print "ERROR: $jobid/$copyid already known as $seen{$jobid}\n";
520                 $ret = 1;
521             } else {
522                 $seen{$jobid}=$copyid;
523                 $nb_found++;
524             }
525         }
526     }
527     
528     # test the number of copies against the given arg
529     if ($nb_to_found && ($nb_to_found != $nb_found)) {
530         print "ERROR: Found wrong number of copies ",
531               "($nb_to_found != $nb_found)\n";
532         exit 1;
533     }
534
535     exit $ret;
536 }
537
538 use POSIX qw/strftime/;
539 sub get_time
540 {
541     my ($sec) = @_;
542     print strftime('%F %T', localtime(time+$sec)), "\n";
543 }
544
545 1;