File Coverage

blib/lib/NBU.pm
Criterion Covered Total %
statement 75 190 39.4
branch 0 58 0.0
condition n/a
subroutine 24 38 63.1
pod n/a
total 99 286 34.6


line stmt bran cond sub pod time code
1             #
2             # Top level entry point for the NBU module set to inspect, report on and
3             # occasionally manipulate a Veritas NetBackup environment.
4             #
5             # Copyright (c) 2002 Paul Winkeler. All Rights Reserved.
6             # This program is free software; you may redistribute it and/or modify it under
7             # the same terms as Perl itself.
8             #
9             package NBU;
10              
11             require 5.005;
12              
13 1     1   1505 use IPC::Open2;
  1         5669  
  1         61  
14              
15 1     1   8 use strict;
  1         2  
  1         34  
16 1     1   4 use Carp;
  1         7  
  1         60  
17              
18 1     1   575 use NBU::Class;
  1         6  
  1         36  
19 1     1   613 use NBU::Retention;
  1         3  
  1         22  
20 1     1   542 use NBU::Media;
  1         4  
  1         38  
21 1     1   573 use NBU::File;
  1         3  
  1         25  
22 1     1   514 use NBU::Pool;
  1         2  
  1         28  
23 1     1   579 use NBU::Image;
  1         3  
  1         27  
24 1     1   499 use NBU::Fragment;
  1         5  
  1         39  
25 1     1   618 use NBU::Mount;
  1         3  
  1         29  
26 1     1   6 use NBU::Host;
  1         2  
  1         20  
27 1     1   5 use NBU::Schedule;
  1         1  
  1         17  
28 1     1   6 use NBU::Robot;
  1         1  
  1         21  
29 1     1   570 use NBU::StorageUnit;
  1         3  
  1         29  
30 1     1   773 use NBU::Job;
  1         5  
  1         42  
31 1     1   745 use NBU::License;
  1         3  
  1         43  
32              
33             BEGIN {
34 1     1   6 use Exporter ();
  1         1  
  1         19  
35 1     1   4 use AutoLoader qw(AUTOLOAD);
  1         2  
  1         7  
36 1     1   37 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $AUTOLOAD);
  1         2  
  1         129  
37 1     1   2 $VERSION = do { my @r=(q$Revision: 1.42 $=~/\d+/g); sprintf "%d."."%02d"x$#r,@r };
  1         6  
  1         8  
38 1         11 @ISA = qw();
39 1         3 @EXPORT_OK = qw();
40 1         88 %EXPORT_TAGS = qw();
41             }
42              
43             my $NBUVersion;
44             my $NBP;
45             my $sudo;
46              
47             my $PS;
48             my $NBdir;
49             my $MMdir;
50              
51             #
52             # Determine the path to the top of the NetBackup binaries
53             if (exists($ENV{"WINDIR"})) {
54              
55             $sudo = "";
56              
57              
58             require Win32::TieRegistry || die "Cannot require Win32::TieRegistry!";
59              
60             *Registry = *Win32::TieRegistry::Registry;
61              
62             # The preferred way to code this is to take control of the Registry symbol
63             # table entry with:
64             # our $Registry;
65             # However that requires at least Perl 5.6 :-(
66 1     1   5 no strict "vars";
  1         2  
  1         1563  
67              
68             my($PATHS) = "HKEY_LOCAL_MACHINE\\SOFTWARE\\VERITAS\\NetBackup\\CurrentVersion\\Paths";
69              
70             $PS = $_ps = $Registry->{ $PATHS . "\\_ps" };
71             if (!defined($PS)) {
72             print STDERR "NetBackup not installed?\n";
73             $NBdir = $MMdir = "";
74             $PS = "/";
75             }
76             else {
77             $NBdir = $Registry->{ $PATHS . "\\_ov_fs" } . "\\\\" .
78             $Registry->{ $PATHS . "\\SM_DIR" } . "\\\\" .
79             $Registry->{ $PATHS . "\\BP_DIR_NAME" };
80             $NBdir =~ s/\$\{_ps\}/$PS/g;
81             $NBdir =~ s/ /\\ /g;
82             $NBdir =~ s/([a-zA-Z]):/\/cygdrive\/$1/;
83              
84             $MMdir = $Registry->{ $PATHS . "\\_ov_fs" } . "\\\\" .
85             $Registry->{ $PATHS . "\\SM_DIR" } . "\\\\" .
86             $Registry->{ $PATHS . "\\VM_DIR_NAME" };
87             $MMdir =~ s/\$\{_ps\}/$PS/g;
88             $MMdir =~ s/ /\\ /g;
89             $MMdir =~ s/([a-zA-Z]):/\/cygdrive\/$1/;
90             }
91             }
92             else {
93             if (-e ($NBP = "/usr/openv")) {
94             $PS = "/";
95             $NBdir = "/usr/openv/netbackup";
96             $MMdir = "/usr/openv/volmgr";
97              
98             #
99             # If we can execute them as is great, else insert sudo
100             $sudo = "";
101             if ((!-x $NBP."/volmgr/bin/vmoprcmd") || (system($NBP."/volmgr/bin/vmoprcmd >/dev/null 2>&1") != 0)) {
102             if (-x "/usr/local/bin/sudo") {
103             $sudo = "/usr/local/bin/sudo ";
104             }
105             else {
106             die "Unable to execute NetBackup binaries\n";
107             }
108             }
109             }
110             else {
111             die "Expected NetBackup installation at $NBP\n";
112             }
113             }
114              
115             my $configFile = "/usr/local/etc/NBU-conf.xml";
116             my @XMLModules = ( "XML::XPath", "XML::XPath::XMLParser");
117             my $NBUConfigXP;
118             if (-f $configFile) {
119             foreach my $m (@XMLModules) {
120             eval "use $m;";
121             }
122             eval { $NBUConfigXP = XML::XPath->new(filename => $configFile); };
123              
124             if (!defined($NBUConfigXP)) {
125             print STDERR "Ignoring configuration file $configFile due to XML loading errors\n";
126             }
127             else {
128             my $nodeset = $NBUConfigXP->find('//host-information/server');
129             foreach my $server ($nodeset->get_nodelist) {
130             my $name = $server->getAttribute('name');
131             my $canonicalName = $server->getAttribute('canonical');
132              
133             NBU::Host->loadAlias($name, $canonicalName);
134             }
135             }
136             }
137              
138             my $debug = undef;
139             sub debug {
140 0     0     my $proto = shift;
141            
142 0 0         if (@_) {
143 0           $debug = shift;
144             }
145 0           return $debug;
146             }
147              
148             my %cmdList = (
149             bpclntcmd => $sudo."${NBdir}${PS}bin${PS}bpclntcmd",
150             bpconfig => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpconfig",
151             bpgetconfig => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpgetconfig",
152             bpclient => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpclient",
153              
154             bpcllist => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bppllist",
155             bpclinfo => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpplinfo",
156             bpclclients => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpplclients",
157              
158             bppllist => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bppllist",
159             bpplinfo => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpplinfo",
160             bpplclients => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpplclients",
161              
162             bpcoverage => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpcoverage",
163             bpflist => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpflist",
164             bpmedialist => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpmedialist",
165             bpdbjobs => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpdbjobs",
166             bpmedia => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpmedia",
167             bpimmedia => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpimmedia",
168             bpimagelist => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpimagelist",
169             bpstulist => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpstulist",
170             bpretlevel => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpretlevel",
171             bperror => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bperror",
172             bpminlicense => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpminlicense",
173              
174             bperrcode => $sudo."${NBdir}${PS}bin${PS}goodies${PS}bperrcode",
175              
176             vmoprcmd => $sudo."${MMdir}${PS}bin${PS}vmoprcmd",
177             vmquery => $sudo."${MMdir}${PS}bin${PS}vmquery",
178             vmchange => $sudo."${MMdir}${PS}bin${PS}vmchange",
179             vmpool => $sudo."${MMdir}${PS}bin${PS}vmpool",
180             vmcheckxxx => $sudo."${MMdir}${PS}bin${PS}vmcheckxxx",
181             vmupdate => $sudo."${MMdir}${PS}bin${PS}vmupdate",
182             vmglob => $sudo."${MMdir}${PS}bin${PS}vmglob",
183             );
184              
185              
186             my $vmchangeDelay = 1;
187             my $lastChange = 0;
188              
189             my $pipeNames = "PIPE00";
190             sub cmd {
191 0     0     my $proto = shift;
192 0           my $cmdline = shift;
193 0           my $biDirectional;
194 0 0         my $quash = exists($ENV{"WINDIR"}) ? "" : " 2> /dev/null ";
195              
196 0           my $originalCmdline = $cmdline;
197             #
198             # Providing one's own trailing pipe is deprecated
199 0           $cmdline =~ s/[\s]*\|[\s]*$//;
200              
201 0 0         if ($cmdline =~ s/^[\s]*\|[\s]*//) {
202 0           $biDirectional = 1;
203             }
204              
205 0           my $cmd = $cmdline;
206 0           my $arglist = "";
207 0 0         if ((my $argoffset = index($cmdline, " ")) >= 0) {
208 0           $cmd = substr($cmdline, 0, $argoffset);
209 0           $arglist = substr($cmdline, $argoffset+1);
210             }
211              
212 0 0         if (!exists($cmdList{$cmd})) {
213 0           print STDERR "Not aware of such a NetBackup command as \"$cmd\" extracted from\n\t$originalCmdline";
214 0           return undef;
215             }
216              
217 0           $cmdline = $cmdList{$cmd}." ".$arglist;
218 0 0         if ($debug) {
219 0 0         print STDERR "Executing: ".(defined($biDirectional) ? "bi-directional " : "")."$cmdline\n";
220             }
221              
222 0 0         if ($cmd eq "vmchange") {
223 0 0         if ((my $gap = time - $lastChange) < $vmchangeDelay) {
224 0 0         print STDERR "Delay ($vmchangeDelay - $gap) for vmchange\n" if ($debug);
225 0           sleep($vmchangeDelay - $gap);
226             }
227 0           $lastChange = time;
228             }
229            
230 0 0         if (defined($biDirectional)) {
    0          
231 0           my $readPipe = $pipeNames++;
232 0           my $writePipe = $pipeNames++;
233 1     1   9 no strict 'refs';
  1         1  
  1         118  
234 0           open2($readPipe, $writePipe, $cmdline.$quash);
235 0           return (*$readPipe{IO}, *$writePipe{IO});
236             }
237             elsif (!@_) {
238 0           my $pipe = $pipeNames++;
239 1     1   6 no strict 'refs';
  1         3  
  1         1687  
240 0           open($pipe, $cmdline.$quash." |");
241 0           return *$pipe{IO};
242             }
243             else {
244 0           system($cmdline."\n");
245 0           return undef;
246             }
247             }
248              
249             my ($me, $master, @servers, @knownMasters);
250             my (
251             $adminAddress, $wakeupInterval,
252             $retryPeriod,
253             $maxClientJobs,
254             $retryCount,
255             $logFileRetentionPeriod,
256             $u1, $u2, $u3, $u4,
257             $immediatePostProcess,
258             $reportDisplayWindow,
259             $TIRRetentionPeriod,
260             $prepInterval
261             );
262              
263             sub loadClusterInformation {
264              
265 0     0     my $myName = "localhost";
266              
267             #
268             # Find out my own name (as far as NetBackup is concerned anyway).
269 0           my $pipe = NBU->cmd("bpclntcmd -self |");
270 0           while (<$pipe>) {
271 0           chop;
272 0 0         if (/gethostname\(\) returned: ([\S]+)/) {
273 0           $myName = $1;
274             }
275             }
276 0           close($pipe);
277              
278             #
279             # Probe around to determine the full set of servers in this NetBackup
280             # environment. First we use bpgetconfig to locate the master in this
281             # environment. Then we use the same program to get the master to re-
282             # gurgitate the full list of servers.
283 0           $master = $me = NBU::Host->new($myName); $myName = $me->name;
  0            
284 0 0         $master = $me->clientOf
285             if ($me->clientOf);
286 0           NBU->addMaster($master);
287 0           $NBUVersion = $me->NBUVersion;
288              
289 0           close($pipe);
290              
291 0           $pipe = NBU->cmd("bpgetconfig -M ".$master->name." |");
292 0           while (<$pipe>) {
293 0 0         if (/SERVER = ([\S]+)/) {
294 0           my $serverName = $1;
295 0           my $server = NBU::Host->new($serverName);
296 0           NBU->addServer($server);
297             }
298 0 0         if (/KNOWN_MASTER = ([^\s,]+)/) {
299 0           my $serverName = $1;
300 0           my $server = NBU::Host->new($serverName);
301 0           NBU->addMaster($server);
302             }
303             }
304 0           close($pipe);
305              
306 0           $pipe = NBU->cmd("bpconfig -M ".$master->name." -l |");
307 0 0         if (defined($_ = <$pipe>)) {
308             (
309 0           $adminAddress, $wakeupInterval,
310             $retryPeriod,
311             $maxClientJobs,
312             $retryCount,
313             $logFileRetentionPeriod,
314             $u1, $u2, $u3, $u4,
315             $immediatePostProcess,
316             $reportDisplayWindow,
317             $TIRRetentionPeriod,
318             $prepInterval
319             ) = split;
320 0 0         $adminAddress = undef if ($adminAddress eq "*NULL*");
321             }
322             }
323              
324             sub addMaster {
325 0     0     my $proto = shift;
326              
327 0 0         if (defined(my $newMaster = shift)) {
328 0           for my $m (@knownMasters) {
329 0 0         return if ($m == $newMaster);
330             }
331 0           push @knownMasters, $newMaster;
332             }
333             }
334              
335             sub addServer {
336 0     0     my $proto = shift;
337              
338 0 0         if (defined(my $newServer = shift)) {
339 0           for my $s (@servers) {
340 0 0         return if ($s == $newServer);
341             }
342 0           push @servers, $newServer;
343             }
344             }
345              
346             sub masters {
347 0     0     my $proto = shift;
348              
349 0 0         loadClusterInformation() if (!defined($me));
350 0           return (@knownMasters);
351             }
352              
353             sub master {
354 0     0     my $proto = shift;
355              
356 0 0         loadClusterInformation() if (!defined($me));
357 0           return ($master == $me);
358             }
359              
360             sub me {
361 0     0     my $proto = shift;
362              
363 0 0         loadClusterInformation() if (!defined($me));
364 0           return $me;
365             }
366              
367             sub servers {
368 0     0     my $proto = shift;
369              
370 0 0         loadClusterInformation() if (!defined($me));
371 0           return @servers;
372             }
373              
374             sub adminAddress {
375 0     0     my $proto = shift;
376              
377 0 0         loadClusterInformation() if (!defined($me));
378 0           return $adminAddress;
379             }
380              
381             sub maxJobsPerClient {
382 0     0     my $proto = shift;
383              
384 0 0         loadClusterInformation() if (!defined($me));
385 0           return $maxClientJobs;
386             }
387              
388             my $msgsLoaded;
389             my %msgs;
390             sub loadErrorMessages {
391 0     0     my $proto = shift;
392              
393 0           $msgsLoaded = 0;
394 0           my $pipe = NBU->cmd("bperrcode |");
395 0           while (<$pipe>) {
396 0           chop;
397 0           my ($code, $msg) = split(/ /, $_, 2);
398 0           $msgs{$code} = $msg;
399 0           $msgsLoaded += 1;
400             }
401 0           close($pipe);
402             }
403              
404             sub errorMessage {
405 0     0     my $proto = shift;
406              
407 0 0         NBU->loadErrorMessages if (!defined($msgsLoaded));
408              
409 0           my $code = shift;
410 0           return $msgs{$code};
411             }
412              
413             sub date {
414 0     0     my $proto = shift;
415 0           my $epochTime = shift;
416              
417 0           my ($s, $m, $h, $mday, $mon, $year, $wday, $yday, $isdst) = localtime($epochTime);
418 0           $year += 1900;
419 0           my $mm = $mon + 1;
420 0           my $dd = $mday;
421 0           my $yyyy = $year;
422              
423 0           return "$mm/$dd/$yyyy $h:$m:$s";
424             }
425              
426             1;
427              
428             __END__