| NBU documentation | Contained in the NBU distribution. |
NBU - Main entry point for NetBackup OO Modules
Solaris
Windows/NT
To come...
This module provides generic support for the entire collection of NBU::* modules. Not only does it ensure that all other modules are properly "use"d but it also provides several methods to these other modules to hide the details of the NetBackup environment.
Winkeler, Paul pwinkeler@pbnj-solutions.com
Copyright (C) 2002 Paul Winkeler
| NBU documentation | Contained in the NBU distribution. |
# # Top level entry point for the NBU module set to inspect, report on and # occasionally manipulate a Veritas NetBackup environment. # # Copyright (c) 2002 Paul Winkeler. All Rights Reserved. # This program is free software; you may redistribute it and/or modify it under # the same terms as Perl itself. # package NBU; require 5.005; use IPC::Open2; use strict; use Carp; use NBU::Class; use NBU::Retention; use NBU::Media; use NBU::File; use NBU::Pool; use NBU::Image; use NBU::Fragment; use NBU::Mount; use NBU::Host; use NBU::Schedule; use NBU::Robot; use NBU::StorageUnit; use NBU::Job; use NBU::License; BEGIN { use Exporter (); use AutoLoader qw(AUTOLOAD); use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $AUTOLOAD); $VERSION = do { my @r=(q$Revision: 1.42 $=~/\d+/g); sprintf "%d."."%02d"x$#r,@r }; @ISA = qw(); @EXPORT_OK = qw(); %EXPORT_TAGS = qw(); } my $NBUVersion; my $NBP; my $sudo; my $PS; my $NBdir; my $MMdir; # # Determine the path to the top of the NetBackup binaries if (exists($ENV{"WINDIR"})) { $sudo = ""; require Win32::TieRegistry || die "Cannot require Win32::TieRegistry!"; *Registry = *Win32::TieRegistry::Registry; # The preferred way to code this is to take control of the Registry symbol # table entry with: # our $Registry; # However that requires at least Perl 5.6 :-( no strict "vars"; my($PATHS) = "HKEY_LOCAL_MACHINE\\SOFTWARE\\VERITAS\\NetBackup\\CurrentVersion\\Paths"; $PS = $_ps = $Registry->{ $PATHS . "\\_ps" }; if (!defined($PS)) { print STDERR "NetBackup not installed?\n"; $NBdir = $MMdir = ""; $PS = "/"; } else { $NBdir = $Registry->{ $PATHS . "\\_ov_fs" } . "\\\\" . $Registry->{ $PATHS . "\\SM_DIR" } . "\\\\" . $Registry->{ $PATHS . "\\BP_DIR_NAME" }; $NBdir =~ s/\$\{_ps\}/$PS/g; $NBdir =~ s/ /\\ /g; $NBdir =~ s/([a-zA-Z]):/\/cygdrive\/$1/; $MMdir = $Registry->{ $PATHS . "\\_ov_fs" } . "\\\\" . $Registry->{ $PATHS . "\\SM_DIR" } . "\\\\" . $Registry->{ $PATHS . "\\VM_DIR_NAME" }; $MMdir =~ s/\$\{_ps\}/$PS/g; $MMdir =~ s/ /\\ /g; $MMdir =~ s/([a-zA-Z]):/\/cygdrive\/$1/; } } else { if (-e ($NBP = "/usr/openv")) { $PS = "/"; $NBdir = "/usr/openv/netbackup"; $MMdir = "/usr/openv/volmgr"; # # If we can execute them as is great, else insert sudo $sudo = ""; if ((!-x $NBP."/volmgr/bin/vmoprcmd") || (system($NBP."/volmgr/bin/vmoprcmd >/dev/null 2>&1") != 0)) { if (-x "/usr/local/bin/sudo") { $sudo = "/usr/local/bin/sudo "; } else { die "Unable to execute NetBackup binaries\n"; } } } else { die "Expected NetBackup installation at $NBP\n"; } } my $configFile = "/usr/local/etc/NBU-conf.xml"; my @XMLModules = ( "XML::XPath", "XML::XPath::XMLParser"); my $NBUConfigXP; if (-f $configFile) { foreach my $m (@XMLModules) { eval "use $m;"; } eval { $NBUConfigXP = XML::XPath->new(filename => $configFile); }; if (!defined($NBUConfigXP)) { print STDERR "Ignoring configuration file $configFile due to XML loading errors\n"; } else { my $nodeset = $NBUConfigXP->find('//host-information/server'); foreach my $server ($nodeset->get_nodelist) { my $name = $server->getAttribute('name'); my $canonicalName = $server->getAttribute('canonical'); NBU::Host->loadAlias($name, $canonicalName); } } } my $debug = undef; sub debug { my $proto = shift; if (@_) { $debug = shift; } return $debug; } my %cmdList = ( bpclntcmd => $sudo."${NBdir}${PS}bin${PS}bpclntcmd", bpconfig => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpconfig", bpgetconfig => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpgetconfig", bpclient => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpclient", bpcllist => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bppllist", bpclinfo => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpplinfo", bpclclients => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpplclients", bppllist => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bppllist", bpplinfo => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpplinfo", bpplclients => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpplclients", bpcoverage => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpcoverage", bpflist => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpflist", bpmedialist => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpmedialist", bpdbjobs => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpdbjobs", bpmedia => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpmedia", bpimmedia => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpimmedia", bpimagelist => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpimagelist", bpstulist => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpstulist", bpretlevel => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpretlevel", bperror => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bperror", bpminlicense => $sudo."${NBdir}${PS}bin${PS}admincmd${PS}bpminlicense", bperrcode => $sudo."${NBdir}${PS}bin${PS}goodies${PS}bperrcode", vmoprcmd => $sudo."${MMdir}${PS}bin${PS}vmoprcmd", vmquery => $sudo."${MMdir}${PS}bin${PS}vmquery", vmchange => $sudo."${MMdir}${PS}bin${PS}vmchange", vmpool => $sudo."${MMdir}${PS}bin${PS}vmpool", vmcheckxxx => $sudo."${MMdir}${PS}bin${PS}vmcheckxxx", vmupdate => $sudo."${MMdir}${PS}bin${PS}vmupdate", vmglob => $sudo."${MMdir}${PS}bin${PS}vmglob", ); my $vmchangeDelay = 1; my $lastChange = 0; my $pipeNames = "PIPE00"; sub cmd { my $proto = shift; my $cmdline = shift; my $biDirectional; my $quash = exists($ENV{"WINDIR"}) ? "" : " 2> /dev/null "; my $originalCmdline = $cmdline; # # Providing one's own trailing pipe is deprecated $cmdline =~ s/[\s]*\|[\s]*$//; if ($cmdline =~ s/^[\s]*\|[\s]*//) { $biDirectional = 1; } my $cmd = $cmdline; my $arglist = ""; if ((my $argoffset = index($cmdline, " ")) >= 0) { $cmd = substr($cmdline, 0, $argoffset); $arglist = substr($cmdline, $argoffset+1); } if (!exists($cmdList{$cmd})) { print STDERR "Not aware of such a NetBackup command as \"$cmd\" extracted from\n\t$originalCmdline"; return undef; } $cmdline = $cmdList{$cmd}." ".$arglist; if ($debug) { print STDERR "Executing: ".(defined($biDirectional) ? "bi-directional " : "")."$cmdline\n"; } if ($cmd eq "vmchange") { if ((my $gap = time - $lastChange) < $vmchangeDelay) { print STDERR "Delay ($vmchangeDelay - $gap) for vmchange\n" if ($debug); sleep($vmchangeDelay - $gap); } $lastChange = time; } if (defined($biDirectional)) { my $readPipe = $pipeNames++; my $writePipe = $pipeNames++; no strict 'refs'; open2($readPipe, $writePipe, $cmdline.$quash); return (*$readPipe{IO}, *$writePipe{IO}); } elsif (!@_) { my $pipe = $pipeNames++; no strict 'refs'; open($pipe, $cmdline.$quash." |"); return *$pipe{IO}; } else { system($cmdline."\n"); return undef; } } my ($me, $master, @servers, @knownMasters); my ( $adminAddress, $wakeupInterval, $retryPeriod, $maxClientJobs, $retryCount, $logFileRetentionPeriod, $u1, $u2, $u3, $u4, $immediatePostProcess, $reportDisplayWindow, $TIRRetentionPeriod, $prepInterval ); sub loadClusterInformation { my $myName = "localhost"; # # Find out my own name (as far as NetBackup is concerned anyway). my $pipe = NBU->cmd("bpclntcmd -self |"); while (<$pipe>) { chop; if (/gethostname\(\) returned: ([\S]+)/) { $myName = $1; } } close($pipe); # # Probe around to determine the full set of servers in this NetBackup # environment. First we use bpgetconfig to locate the master in this # environment. Then we use the same program to get the master to re- # gurgitate the full list of servers. $master = $me = NBU::Host->new($myName); $myName = $me->name; $master = $me->clientOf if ($me->clientOf); NBU->addMaster($master); $NBUVersion = $me->NBUVersion; close($pipe); $pipe = NBU->cmd("bpgetconfig -M ".$master->name." |"); while (<$pipe>) { if (/SERVER = ([\S]+)/) { my $serverName = $1; my $server = NBU::Host->new($serverName); NBU->addServer($server); } if (/KNOWN_MASTER = ([^\s,]+)/) { my $serverName = $1; my $server = NBU::Host->new($serverName); NBU->addMaster($server); } } close($pipe); $pipe = NBU->cmd("bpconfig -M ".$master->name." -l |"); if (defined($_ = <$pipe>)) { ( $adminAddress, $wakeupInterval, $retryPeriod, $maxClientJobs, $retryCount, $logFileRetentionPeriod, $u1, $u2, $u3, $u4, $immediatePostProcess, $reportDisplayWindow, $TIRRetentionPeriod, $prepInterval ) = split; $adminAddress = undef if ($adminAddress eq "*NULL*"); } } sub addMaster { my $proto = shift; if (defined(my $newMaster = shift)) { for my $m (@knownMasters) { return if ($m == $newMaster); } push @knownMasters, $newMaster; } } sub addServer { my $proto = shift; if (defined(my $newServer = shift)) { for my $s (@servers) { return if ($s == $newServer); } push @servers, $newServer; } } sub masters { my $proto = shift; loadClusterInformation() if (!defined($me)); return (@knownMasters); } sub master { my $proto = shift; loadClusterInformation() if (!defined($me)); return ($master == $me); } sub me { my $proto = shift; loadClusterInformation() if (!defined($me)); return $me; } sub servers { my $proto = shift; loadClusterInformation() if (!defined($me)); return @servers; } sub adminAddress { my $proto = shift; loadClusterInformation() if (!defined($me)); return $adminAddress; } sub maxJobsPerClient { my $proto = shift; loadClusterInformation() if (!defined($me)); return $maxClientJobs; } my $msgsLoaded; my %msgs; sub loadErrorMessages { my $proto = shift; $msgsLoaded = 0; my $pipe = NBU->cmd("bperrcode |"); while (<$pipe>) { chop; my ($code, $msg) = split(/ /, $_, 2); $msgs{$code} = $msg; $msgsLoaded += 1; } close($pipe); } sub errorMessage { my $proto = shift; NBU->loadErrorMessages if (!defined($msgsLoaded)); my $code = shift; return $msgs{$code}; } sub date { my $proto = shift; my $epochTime = shift; my ($s, $m, $h, $mday, $mon, $year, $wday, $yday, $isdst) = localtime($epochTime); $year += 1900; my $mm = $mon + 1; my $dd = $mday; my $yyyy = $year; return "$mm/$dd/$yyyy $h:$m:$s"; } 1; __END__