Veritas-bu

[Veritas-bu] Report functionality in NetBackup

2001-07-06 09:52:29
Subject: [Veritas-bu] Report functionality in NetBackup
From: RYAN_ANDERSON AT udlp DOT com (RYAN ANDERSON)
Date: Fri, 6 Jul 2001 08:52:29 -0500
This is a multi-part message in MIME format.
--------------0B077D41D83DB774C1DAA711
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

John,

Thanks much, the changes you made work great. Thanks (of course) to Rob
Worman for writing it and letting it be distributed. Attached is Rob's
script with John's changes.

Regards,

RCA

John Meyers wrote:
> 
>  I just tried out the reporting script backup_report.pl and ran into some
>  problems.  Basically the Gbytes reported was incorrect and the summarys
>  weren't printing as expected.  I had jobs backing up ~ 30 Mbytes that were
>  reporting 3+ Gbytes.
> 
>  I thought I would pass along the changes I made to get this working as
>  expected in case anyone is interested.
> 
>  Code changes:
> 
>  After the following comment, add the next to lines, (approx line 38)
> 
>  ############
>  # Grab any flags or switches that
>  # may have been passed from the
>  # command line
>  ############
>  $omit_fulls = 0;
>  $omit_incs = 0;
> 
>  Change the line that begins with (approximately line 230),
> 
>       if ($type =~ /Full/) {
>  to
>       if ($type =~ /full/i) {
> 
>  change (approx line 240)
> 
>       elsif ($type =~ /Incremental/) {
>  to
>       elsif ($type =~ /incr/i) {
> 
>  To fix the total Gbytes field, make the following changes, (approx line 366)
> 
>      $end= $jobs_hash{$job}[5];
>      $gbytes= $jobs_hash{$job}[4];
>      $gbytes= sprintf ("%6.4f", $gbytes);               # <- add this line
>      $elapsed= $jobs_hash{$job}[6];
> 
>  That should take care of if.  If you don't want a 20 digit Gbyte value under
>  the summary, you could probably also add a similiar sprintf statement for the
>  $total_full_gb and $total_inc_gb variables prior to the print statements.
> 
>  Cheers.
> 
>  John Meyers
>  Computing Services
>  Wright State University
>  E-mail: john.meyers AT wright DOT edu

--
Ryan C. Anderson       | United Defense L.P.
ryan_anderson AT udlp DOT com | pager 952.235.9936
--------------0B077D41D83DB774C1DAA711
Content-Type: application/x-perl;
 name="backup_report.pl"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="backup_report.pl"

#!/usr/local/bin/perl
#
# $Id: backup_report.pl,v 1.1 1999/03/01 19:16:37 cswormr Exp $
#
# $Log: backup_report.pl,v $
# Revision 1.1  1999/03/01 19:16:37  cswormr
# Initial revision
#
#
# This script generates a formatted report of backup activity
# including client/class/start time/gigabytes/end time/elapsed time
#
############################
$usage_msg = "usage: backup_report.pl -mail<user1,user2,user3> [-help|-h] 
[-nofulls] [-noincrementals] [-weekend] [-start<DD/MM/YY>] [-end<DD/MM/YY>]\n\n
-help, -h           :   produces this message

-mail<user1,user2,user3>  :  who receives the report email

-nofulls        :   report only incremental (and obackup) backup jobs
-noincrementals :   report only full backup jobs

-weekend        :   report the previous 2 days of backups (instead
                    of the default 1 day)

-start<DD/MM/YY> :   desired start date for your report
-end<DD/MM/YY>   :   desired end date for your report

 
If no date arguments are provided, the script will
report on backups that occurred from 7am yesterday 
to 7am today.  Otherwise, BOTH start and end must 
be provided.\n\n";
############################

############
# Grab any flags or switches that
# may have been passed from the
# command line
############
$omit_fulls = 0;
$omit_incs = 0;

while ($_ = $ARGV[0], /^-/) {
    shift;
    last if /^--$/;
    if (/^-help/ || /^-h$/) { die "$usage_msg" }
    
    if (/^-nofulls/) { $omit_fulls = 1 }
    if (/^-noincrementals/) { $omit_incs = 1 }

    if (/^-start(.*)/) { $start_date = $1 }
    if (/^-end(.*)/) { $end_date = $1 }

    if (/^-mail(.*)/) { $mail_to = $1 }

    if (/^-weekend/) { $weekend = 1 }
}

if ($mail_to eq "") {die "$usage_msg"}

############
# In case there were no "start" or "end"
# flags provided, set end_date to today
# and start_date to yesterday, UNLESS
# the $weekend flag is set, in which
# case start_date is set to TWO days ago
############
if ($start_date eq "" || $end_date eq "") {    

    $end_day = (localtime) [3];
    $end_mon = (localtime) [4] + 1;
    $end_yr = (localtime) [5];

    if ($weekend) {
        ($a,$b,$c,$start_day,$start_mon,$start_yr,$d,$e,$f) = 
localtime(time-172800);
    }
    else {
        ($a,$b,$c,$start_day,$start_mon,$start_yr,$d,$e,$f) = 
localtime(time-86400);
    }

    $start_yr = ($start_yr + 1900) % 100;
    $start_yr =~ s/^([0-9])$/0$1/;              # left pad with 0
    $end_yr = ($end_yr + 1900) % 100;
    $end_yr =~ s/^([0-9])$/0$1/;                # left pad with 0

    $start_date = $start_mon+1 . "/" . $start_day . "/" . $start_yr;
    $end_date = $end_mon . "/" . $end_day . "/" . $end_yr;
}

$report_cmd = "/usr/openv/netbackup/bin/admincmd/bpimagelist";
$error_cmd = "/usr/openv/netbackup/bin/admincmd/bperror";
$error_codes = "/usr/openv/scripts/error_codes";
use Sys::Hostname;
$server = hostname();
$mail = "/bin/mailx";
$imagefile = "/tmp/imagelist.tmp";
$errorfile = "/tmp/errorlist.tmp";
$report_file = "report.txt";

#######################
#run the NetBackup reports to grab the raw data
#######################
system("$report_cmd -A -d $start_date 7:00 -e $end_date 7:00 > $imagefile \n");
system("$error_cmd -l -d $start_date 7:00 -e $end_date 7:00 > $errorfile \n");

#######################
#parse the list of backup status
#messages and build a list of all
#the failures
#######################
open(ERRORS,"$errorfile") || warn "Could not open $errorfile:$!";
$failed_found = 0;

LINE: while (<ERRORS>) {
     chop;
     next LINE if (!/EXIT STATUS/);

     ($error_stamp, $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $error_client, $k, 
$error_class, $l, $error_schedule, $m, $n, $exit_status, $therest) = split / 
+/, $_, 20;

     next LINE if ($exit_status < 2);
     # need to do this for NetApps, since they are backed up over NFS,
     # the client name wouldn't be correct otherwise
     if ($error_class =~ /tyr_/) { $error_client = "tyr"; }
     elsif ($error_class =~ /heimdall_/) { $error_client = "heimdall"; }

     # construct the following tmp array:
     #      0= start_time (MM/DD/YY HH:MM:SS)
     #      1= client (machine name, e.g. merlin)
     #      2= class name (class name, e.g. merlin_data)
     #      3= schedule (Full, Incremental, etc)
     #      4= exit status (some number >1)
     #
     # @tmp is then put in a hash called "failed_hash", with
     # back_id as the key, where back_id always
     # looks like "hostname_timestamp"

     $failed_found = 1;
     $error_back_id = $error_client . "_" . $error_stamp;
     $error_start_time = &stamp2time($error_stamp);

     $error_tmp[0] = $error_start_time;
     $error_tmp[1] = $error_client;
     $error_tmp[2] = $error_class;
     $error_tmp[3] = $error_schedule;
     $error_tmp[4] = $exit_status;

     $failed_hash{$error_back_id} = [ @error_tmp ];

}
close ERRORS;


#######################
#parse the list of successful backups
#and build our hash of successes.
#######################
open(IMAGES,"$imagefile") || warn "Could not open $imagefile:$!";

$last_full = $last_incremental = "";
$first_full = $first_incremental = 9999999999;
$total_full_gb = $total_inc_gb = 0;

LINE2:  while (<IMAGES>) {
    chop;
    if (/^Backup ID: /) { $back_id = &get_val($_);  }
    if (/^Client: /) { $client = &get_val($_);  }
    elsif (/^Class:/) { $class = &get_val($_); }
    elsif (/^Sched Label:/) { $type = &get_val($_); }
    elsif (/^Kilobytes:/) { $kb = &get_val($_); }
    elsif (/^Backup Time:/) { $start_time = &get_val($_);}
    elsif (/^Elapsed Time:/) { $elapsed = &get_val($_); }
    elsif (/^$/) {
        
      # this will prevent an initial CR in the report from
      # generating a bogus entry.
      next LINE2 if $back_id eq "";

      # the local backup of the backup master server should
      # be ignored.  (hopefully, these classes names won't
      # change......)
      next LINE2 if $class eq "master_local";

      # this is where we ignore fulls or incrementals, based on the command 
line switches
      next LINE2 if $omit_fulls && $type =~ /Full/;
      next LINE2 if $omit_incs && ($type =~ /Incremental/ || $class =~ 
/nitti_online_Oracle/);

      # need to do this for NetApps, since they are backed up over NFS, 
      # the client name wouldn't be correct otherwise
      if ($class =~ /tyr_/) { $client = "tyr"; }
      elsif ($class =~ /heimdall_/) { $client = "heimdall"; }

      # construct the following tmp array:
      #      0= start_time (MM/DD/YY HH:MM:SS)
      #      1= client (machine name, e.g. merlin)
      #      2= class name (class name, e.g. merlin_data)
      #      3= schedule (Full, Incremental, etc)
      #      4= gb (gigabytes backed up)
      #      5= end_time (MM/DD/YY HH:MM:SS)
      #      6= elapsed (HH:MM:SS)
      #
      # @tmp is then put in a hash called "jobs_hash", with
      # back_id as the key, where back_id always
      # looks like "hostname_timestamp"

      $gb = $kb/1024/1024;
      ($junk,$start_stamp) = split /_/, $back_id, 2; 

      $end_stamp = &sumtime($start_stamp,$elapsed);
      $end_time = &stamp2time($end_stamp);

      # if this is being run on athena, we need to look at
      # the oracle/obackup jobs, too.  We will treat these
      # like incrementals, while renaming the type "Oracle"
      # to replace "user_directed"
      # 
      if ($class =~ /nitti_online_Oracle/) { 
         $total_inc_gb = $total_inc_gb + $gb;
         $type = "Oracle";
        
         # check to see if this is the earliest job in the output
        if ($start_stamp < $first_incremental) {
           $first_incremental = $start_stamp;
        }
         # check to see if this is the latest job in the output
        if ($end_stamp > $last_incremental) {
           $last_incremental = $end_stamp;
        }
      }

      if ($type =~ /full/i) { 
         $total_full_gb = $total_full_gb + $gb;
         # check to see if this is the earliest job in the output
        if ($start_stamp < $first_full) {
           $first_full = $start_stamp;
        }
         # check to see if this is the latest job in the output
        if ($end_stamp > $last_full) {
           $last_full = $end_stamp;
        }
      }

     elsif ($type =~ /incr/i) {
         $total_inc_gb = $total_inc_gb + $gb;
         $type = "Incr.";
         # check to see if this is the earliest job in the output
        if ($start_stamp < $first_incremental) {
           $first_incremental = $start_stamp;
        }
 
         # check to see if this is the latest job in the output
        if ($end_stamp > $last_incremental) {
           $last_incremental = $end_stamp;
        }
      }

       
      $tmp[0] = $start_time;
      $tmp[1] = $client;
      $tmp[2] = $class;
      $tmp[3] = $type;
      $tmp[4] = $gb;
      $tmp[5] = $end_time;
      $tmp[6] = $elapsed;
 
      $jobs_hash{$back_id} = [ @tmp ];
 
      $client=$class=$type=$kb=$end=$elapsed="";
    } #elsif "^$"
} #while
close IMAGES;

#
# printing of the report header
# begins here, we use the first_
# and last_ variables in the
# header, but we need to convert
# them from epoch time to human
# readable dates
#
$first_full_time = &stamp2time($first_full);
$last_full_time = &stamp2time($last_full);
$first_incremental_time = &stamp2time($first_incremental);
$last_incremental_time = &stamp2time($last_incremental);

open(REPORT,">$report_file");
 
print REPORT "               Backup Report - $server ($start_date - $end_date) 
\n\n";


############
# the other place where those command
# line switches have an effect.
# If "-nofulls" or "-noincrementals"
# was specified at the command line,
# then there won't be a summary line
# printed.
############

if (!$omit_fulls && $last_full) {
    print REPORT "                   Summary - Fulls:\n\n";
    print REPORT "Started              Finished             Total GB Backed 
Up\n#################    #################    ################\n";
    print REPORT "$first_full_time    $last_full_time    $total_full_gb\n\n";
}

if (!$omit_incs && $last_incremental) {
    print REPORT "                   Summary - Incrementals:\n\n";
    print REPORT "Started              Finished             Total GB Backed 
Up\n#################    #################    ################\n";
    print REPORT "$first_incremental_time    $last_incremental_time    
$total_inc_gb\n\n";
}

############
# dump out the failed backups
############
use FileHandle;
REPORT->format_name("ERRORS");
REPORT->format_top_name("ERRORS_TOP");

if ($failed_found) {
   foreach $job ( sort keys %failed_hash ) {
 
     $error_client= $failed_hash{$job}[1];
     $error_class= $failed_hash{$job}[2];
     $error_type= $failed_hash{$job}[3];
     $exit_status= $failed_hash{$job}[4];
     $error_start_time= $failed_hash{$job}[0];

     $errors_to_print{$exit_status} = 1;
 
     write REPORT;
   } #foreach
}
else {
   $error_client= "No Problems";
   $error_class = "";
   $error_type = "";
   $exit_status = "";
   $error_start_time = "";

   write REPORT;
} 

format_lines_left REPORT 0;

REPORT->format_name("ERROR_TEXT");
REPORT->format_top_name("ERROR_TEXT_TOP");
slurp_error_text();
foreach $error (sort {$a <=> $b} keys %errors_to_print) {
   write REPORT;
}

format_lines_left REPORT 0;

############
# dump out the successful backups
############
REPORT->format_name("REPORT");
REPORT->format_top_name("REPORT_TOP");

foreach $job ( sort keys %jobs_hash ) {
 
     $client= $jobs_hash{$job}[1];
     $class= $jobs_hash{$job}[2];
     $type= $jobs_hash{$job}[3];
     $start= $jobs_hash{$job}[0];
     $end= $jobs_hash{$job}[5];
     $gbytes= $jobs_hash{$job}[4];
         $gbytes= sprintf ("%6.4f", $gbytes);
     $elapsed= $jobs_hash{$job}[6];

$start_time = substr($start, 9, 8);
$end_time = substr($end, 9, 8);
 
     write REPORT;
} #foreach

close REPORT;

#system("/usr/bin/cat $error_codes >> $report_file");
system("$mail -s \"Backup Report - $server\" $mail_to < $report_file");

############
#  end of the actual program
############


###########
# Reports and subroutines below
########### 

format ERRORS_TOP = 
               The following backups had problems:
    (three entries for a client probably means that client failed completely)

Client       Class               Type    Start Time         Exit Status
=======================================================================
.


format ERRORS = 
@<<<<<<<<<<  @<<<<<<<<<<<<<<<<<  @<<<<<  @<<<<<<<<<<<<<<<<      @<<<
$error_client,$error_class,$error_type,$error_start_time,$exit_status
.


format ERROR_TEXT_TOP =

Error Codes
=======================================================================
.


format ERROR_TEXT =
@<<< 
@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$error, $error_text{$error}
.


format REPORT_TOP = 

               The following backups were successful:

                                         Start     End
Client       Class               Type    Time      Time      Elapsed    GBytes
==============================================================================
.


format REPORT = 
@<<<<<<<<<<  @<<<<<<<<<<<<<<<<<  @<<<<<  @<<<<<<<  @<<<<<<<  @<<<<<<<<  @<<<<
$client,     $class,             $type,  $start_time,$end_time,$elapsed,  
$gbytes
.

########
# this subroutine is given a line of text
# (in this case, a line of bpimagelist output)
# and returns everything (minus leading whitespace)
# after the colon.  e.g.
#
#    "Client:     ewok"
# 
# would return as just "ewok"
########
sub get_val {
   my ($str) = @_;
   $str =~ s/^.*?://;
   $str =~ s/   *//g;
   return $str;
}

#########
# this subroutine is given an epoch-style
# date (10 digits, seconds since 1970) and
# returns the equivalent date as "MM/DD/YY HH:MM:SS"
# e.g. if it is passed "0918799217", it will return
# "02/12/99 00:00:17"
#########

sub stamp2time {

my ($stamp) = @_;

($tmp_sec,$tmp_min,$tmp_hour,$tmp_day,$tmp_month,$tmp_year,$a,$b,$c) = 
localtime($stamp);
$tmp_month = $tmp_month + 1;
$tmp_year = ($tmp_year + 1900) % 100;

#don't really need to do this, but it makes for a
#prettier report.  (turns 2/3/99 23:6:9 into 02/03/99 23:06:09)
#
foreach $item ($tmp_sec,$tmp_min,$tmp_hour,$tmp_day,$tmp_month,$tmp_year) {
$item =~ s/^([0-9])$/0$1/;
}

$time = $tmp_month . "/" . $tmp_day . "/" . $tmp_year . " " . $tmp_hour . ":" . 
$tmp_min . ":" . $tmp_sec;
 
return $time;
}

#########
# this subroutine is given a human-readable
# date (MM/DD/YY HH:MM:SS) and returns the
# equivalent epoch-style date (10 digits, 
# seconds since 1970) 
# e.g. if it is passed  "02/12/99 00:00:17",
# it will return "0918799217"
#########
sub time2stamp {

my ($time) = @_;

use Time::Local;
($tmp_date,$tmp_time) = split / /, $time, 2;
($tmp_month,$tmp_day,$tmp_year) = split /\//, $tmp_date, 3;
($tmp_hour,$tmp_min,$tmp_sec) = split /:/,$tmp_time, 3;

$stamp = timelocal($tmp_sec,$tmp_min,$tmp_hour,$tmp_day,$tmp_month-1,$tmp_year);
 
return $stamp;
}

##########
# this subroutine is given two
# parameters - an epoch start time
# and an elapsed time in the form
# of HH:MM:SS.  The returned value
# is an epoch time that represents
# start + elapsed
##########
sub sumtime {

my ($s_stamp) = @_[0];
my ($e_hours,$e_min,$e_sec) = split /:/,@_[1], 3;

$e_seconds = $e_sec + 60*$e_min + 3600*$e_hours;
$sum = $s_stamp + $e_seconds;

return $sum;
}

#
# Slurp error text into an array for use later:
sub slurp_error_text {
    undef %error_text;
    open(E, $error_codes);
    while (<E>) {
        if (/^[0-9]/) {
            chomp;
            ($num, $text) = split(/\s+/, $_, 2);
            $error_text{$num} = $text;
        }
    }
    close(E);
}

--------------0B077D41D83DB774C1DAA711--


<Prev in Thread] Current Thread [Next in Thread>