| 1 | rodolico | 1 | #! /usr/bin/perl
 | 
        
           |  |  | 2 |   | 
        
           |  |  | 3 | my @errors;
 | 
        
           |  |  | 4 | my @fileList;
 | 
        
           |  |  | 5 | my %backupDomains; # loaded from configuration file
 | 
        
           |  |  | 6 | my $MISSING_BACKUP_MAILTO; # loaded from configuration file
 | 
        
           |  |  | 7 | my $TESTING = 0;
 | 
        
           |  |  | 8 |   | 
        
           |  |  | 9 | # standard find and load configuration file
 | 
        
           |  |  | 10 | sub loadConfigurationFile {
 | 
        
           |  |  | 11 |    my $configuration_file = shift;
 | 
        
           |  |  | 12 |   | 
        
           |  |  | 13 |    use File::Basename;
 | 
        
           |  |  | 14 |    use Cwd qw(realpath);
 | 
        
           |  |  | 15 |   | 
        
           |  |  | 16 |    my $filename  = realpath($0); # get my real path
 | 
        
           |  |  | 17 |    my $directories;
 | 
        
           |  |  | 18 |    my $suffix;
 | 
        
           |  |  | 19 |    #print "$configuration_file\n";
 | 
        
           |  |  | 20 |    $configuration_file = $filename unless $configuration_file;
 | 
        
           |  |  | 21 |    #print "$configuration_file\n";
 | 
        
           |  |  | 22 |   | 
        
           |  |  | 23 |    if ( $configuration_file !~ m/\// ) { # no path information
 | 
        
           |  |  | 24 |       ($filename, $directories, $suffix) = fileparse($filename,qr/\.[^.]*/); # break filename apart
 | 
        
           |  |  | 25 |       #print "No Path Given\n";
 | 
        
           |  |  | 26 |    } else {
 | 
        
           |  |  | 27 |       ($filename, $directories, $suffix) = fileparse($configuration_file,qr/\.[^.]*/); # break filename apart
 | 
        
           |  |  | 28 |       $configuration_file = '';
 | 
        
           |  |  | 29 |       #print "Path included\n";
 | 
        
           |  |  | 30 |    }
 | 
        
           |  |  | 31 |    unless (-e $directories . ($configuration_file ? $configuration_file : $filename) . '.conf' ) {
 | 
        
           |  |  | 32 |       $lookingIn = $directories;
 | 
        
           |  |  | 33 |       while ($lookingIn) {
 | 
        
           |  |  | 34 |          $lookingIn =~ m/^(.*\/)[^\/]+\//;
 | 
        
           |  |  | 35 |          $lookingIn = $1;
 | 
        
           |  |  | 36 |          #print "$lookingIn\n";
 | 
        
           |  |  | 37 |          if (-e $lookingIn . ($configuration_file ? $configuration_file : $filename) . '.conf' ) {
 | 
        
           |  |  | 38 |             $directories = $lookingIn;
 | 
        
           |  |  | 39 |             $lookingIn = '';
 | 
        
           |  |  | 40 |          }
 | 
        
           |  |  | 41 |       }
 | 
        
           |  |  | 42 |    }
 | 
        
           |  |  | 43 |    $configuration_file = $directories . ($configuration_file ? $configuration_file : $filename) . '.conf'; # add the .conf
 | 
        
           |  |  | 44 | #   print "$configuration_file\n";
 | 
        
           |  |  | 45 | #   die;
 | 
        
           |  |  | 46 |    open CONFFILE, "<$configuration_file" or die "Can not open configuration file $configuration_file";
 | 
        
           |  |  | 47 |    my $confFileContents = join( '', <CONFFILE> );
 | 
        
           |  |  | 48 |    close CONFFILE;
 | 
        
           |  |  | 49 |    return $confFileContents;
 | 
        
           |  |  | 50 | }
 | 
        
           |  |  | 51 |   | 
        
           |  |  | 52 | sub processFile {
 | 
        
           |  |  | 53 |    my ($filename,$deviceID, $reportDate) = @_;
 | 
        
           |  |  | 54 |    return '' unless $filename and $deviceID and $reportDate;
 | 
        
           |  |  | 55 |   | 
        
           |  |  | 56 |    open DATA, "<$filename" or die "Could not open $filename: $!";
 | 
        
           |  |  | 57 |    my $line;
 | 
        
           |  |  | 58 |    my %stats;
 | 
        
           |  |  | 59 |    my $backupVersion;
 | 
        
           |  |  | 60 |    # get header
 | 
        
           |  |  | 61 |    print "Starting $filename\n";
 | 
        
           |  |  | 62 |    $stats{'version'} = 'unk';
 | 
        
           |  |  | 63 |    while (($line = <DATA>)) {
 | 
        
           |  |  | 64 |       last if ($line =! m/file list/);
 | 
        
           |  |  | 65 |       if ($line =~ m/backup v([0-9a-z.]+)/) {
 | 
        
           |  |  | 66 |          $stats{'version'} = qq/'$1'/;
 | 
        
           |  |  | 67 |       }
 | 
        
           |  |  | 68 |    }
 | 
        
           |  |  | 69 |    my $linecount = 0;
 | 
        
           |  |  | 70 |    while ($line = <DATA>) {
 | 
        
           |  |  | 71 |       chomp $line;
 | 
        
           |  |  | 72 |       last if $line !~ m/^\s*$/; # on non-blank line exit after 
 | 
        
           |  |  | 73 |    }
 | 
        
           |  |  | 74 |    if ($line !~ m/^Backup Version/ ) { # we found actual file transfer stuff
 | 
        
           |  |  | 75 |       #print "\tProcessing internal lines, previous was\n\t$line\n";
 | 
        
           |  |  | 76 |       while ($line = <DATA>) {
 | 
        
           |  |  | 77 |          $linecount++;
 | 
        
           |  |  | 78 |          last if $line =~ m/^\s*$/;
 | 
        
           |  |  | 79 |          last if $line =~ m/^(Number of Files:)|(Backup Version)/;
 | 
        
           |  |  | 80 |          if ($line =~ m/^deleting/i ) {
 | 
        
           |  |  | 81 |          $stats{'files_deleted'}++;
 | 
        
           |  |  | 82 |          } elsif ($line !~ m/\/$/) { # not a directory, but a real file
 | 
        
           |  |  | 83 |          $stats{'updated'}++;
 | 
        
           |  |  | 84 |          }
 | 
        
           |  |  | 85 |       }
 | 
        
           |  |  | 86 |    }
 | 
        
           |  |  | 87 |    $stats{'files_deleted'} = 0 unless defined $stats{'files_deleted'};
 | 
        
           |  |  | 88 |    $stats{'files_count'} = $linecount;
 | 
        
           |  |  | 89 |    foreach $key ('files_size','transferred_count','transferred_size','data_received', 'data_sent','StorageSize') {
 | 
        
           |  |  | 90 |       $stats{$key} = 0 unless defined $stats{$key};
 | 
        
           |  |  | 91 |    }
 | 
        
           |  |  | 92 |   | 
        
           |  |  | 93 |    while ($line = <DATA>) {
 | 
        
           |  |  | 94 |       chomp $line;
 | 
        
           |  |  | 95 |       if ($line =~ m/Number of files:\s+(\d+)/) {
 | 
        
           |  |  | 96 |          $stats{'files_count'} = $1;
 | 
        
           |  |  | 97 |       } elsif ($line =~ m/Number of files transferred:\s+(\d+)/) {
 | 
        
           |  |  | 98 |          $stats{'transferred_count'} = $1;
 | 
        
           |  |  | 99 |       } elsif ($line =~ m/Total file size:\s+(\d+)\s+bytes/) {
 | 
        
           |  |  | 100 |          $stats{'files_size'} = $1;
 | 
        
           |  |  | 101 |       } elsif ($line =~ m/Total transferred file size:\s+(\d+)\s+bytes/) {
 | 
        
           |  |  | 102 |          $stats{'transferred_size'} = $1;
 | 
        
           |  |  | 103 |       } elsif ($line =~ m/sent\s+(\d+)\s+bytes\s+received\s+(\d+)\s+bytes\s+([0-9.]+)\s+bytes\/sec/) {
 | 
        
           |  |  | 104 |          $stats{'data_sent'} = $1;
 | 
        
           |  |  | 105 |          $stats{'data_received'} = $2;
 | 
        
           |  |  | 106 |       } elsif ($line =~ m/^Begin\s+(\d+)\s*\[(\d+)\]/){
 | 
        
           |  |  | 107 |          $stats{'start_time'} = qq/'$1'/;
 | 
        
           |  |  | 108 |       } elsif ($line =~ m/^Complete\s+(\d+)\s*\[(\d+)\]/){
 | 
        
           |  |  | 109 |          $stats{'end_time'} = qq/'$1'/;
 | 
        
           |  |  | 110 |       } elsif ($line =~ m/^Duration\s+([\d:]+)\s+\[(\d+) seconds\]/){
 | 
        
           |  |  | 111 |          $stats{'Duration'} = $2;
 | 
        
           |  |  | 112 |       } elsif ($line =~ m/^(\d+)\[(\d+)\] began/ ) {
 | 
        
           |  |  | 113 |          $stats{'start_time'} = qq/'$1'/;
 | 
        
           |  |  | 114 |       } elsif ($line =~ m/^(\d+)\[(\d+)\] finished/ ) {
 | 
        
           |  |  | 115 |          $stats{'end_time'} = qq/'$1'/;
 | 
        
           |  |  | 116 |       } elsif ($line =~ m/Backup Version ([0-9.]+)/) {
 | 
        
           |  |  | 117 |          $stats{'version'} = qq/'$1'/;
 | 
        
           |  |  | 118 |       } elsif ($line =~ m/Directory Size On Server: ([0-9.]+) bytes/ ) {
 | 
        
           |  |  | 119 |          $stats{'StorageSize'} = $1;
 | 
        
           |  |  | 120 |       }
 | 
        
           |  |  | 121 |    }
 | 
        
           |  |  | 122 |    # make sure all columns have a value
 | 
        
           |  |  | 123 |    if  ($stats{'start_time'} && $stats{'end_time'} && $stats{'version'}) {
 | 
        
           |  |  | 124 |   | 
        
           |  |  | 125 |       return qq/insert into backups_run (backups_id,report_date,start_time,end_time,version,
 | 
        
           |  |  | 126 |                                           files_count,files_size,transferred_count,
 | 
        
           |  |  | 127 |                                           transferred_size,files_deleted,
 | 
        
           |  |  | 128 |                                           data_sent,data_received,disk_used)
 | 
        
           |  |  | 129 |                            select backups_id, 
 | 
        
           |  |  | 130 |                                     '$reportDate',
 | 
        
           |  |  | 131 |                                     $stats{'start_time'},
 | 
        
           |  |  | 132 |                                     $stats{'end_time'},
 | 
        
           |  |  | 133 |                                     $stats{'version'},
 | 
        
           |  |  | 134 |                                     $stats{'files_count'},
 | 
        
           |  |  | 135 |                                     $stats{'files_size'},
 | 
        
           |  |  | 136 |                                     $stats{'transferred_count'},
 | 
        
           |  |  | 137 |                                     $stats{'transferred_size'},
 | 
        
           |  |  | 138 |                                     $stats{'files_deleted'},
 | 
        
           |  |  | 139 |                                     $stats{'data_sent'},
 | 
        
           |  |  | 140 |                                     $stats{'data_received'},
 | 
        
           |  |  | 141 |                                     $stats{'StorageSize'}
 | 
        
           |  |  | 142 |                            from backups
 | 
        
           |  |  | 143 |                            where device_id = $deviceID/;
 | 
        
           |  |  | 144 |    } else {
 | 
        
           |  |  | 145 |       print "Error Processing $filename\n";
 | 
        
           |  |  | 146 |       foreach $key ('start_time','end_time','version','files_count','files_size','transferred_count','transferred_size','files_deleted','data_sent','data_received') {
 | 
        
           |  |  | 147 |          print "\t$key = [$stats{$key}]\n";
 | 
        
           |  |  | 148 |       }
 | 
        
           |  |  | 149 |       print "\n";
 | 
        
           |  |  | 150 |       return '';
 | 
        
           |  |  | 151 |    }
 | 
        
           |  |  | 152 | }
 | 
        
           |  |  | 153 |   | 
        
           |  |  | 154 |   | 
        
           |  |  | 155 | sub getAttachments{
 | 
        
           |  |  | 156 |    opendir (DATADIR,$sourceDir)  || die "can't opendir $sourceDir: $!"; # read the directory
 | 
        
           |  |  | 157 |    #print "Opened $sourceDir\n";
 | 
        
           |  |  | 158 |    while ( my $thisFile = readdir(DATADIR) ) { # for each file
 | 
        
           |  |  | 159 |       next if $thisFile =~ m/^\./; # skip if it is a "dot" file
 | 
        
           |  |  | 160 |       #print "It is not a dot file\n";
 | 
        
           |  |  | 161 |       next unless -f "$sourceDir/$thisFile";
 | 
        
           |  |  | 162 |       $thisFile = $sourceDir . '/' . $thisFile; # ok, get fully qualified path/filename
 | 
        
           |  |  | 163 |       #print "Preparing $thisFile\n";
 | 
        
           |  |  | 164 |       `munpack -f -C $tempDir < '$thisFile'`;
 | 
        
           |  |  | 165 |       &postProcess($thisFile);
 | 
        
           |  |  | 166 |    }
 | 
        
           |  |  | 167 |    closedir(DATADIR);
 | 
        
           |  |  | 168 |    `rm -f $tempDir/*.desc`;
 | 
        
           |  |  | 169 |    `gunzip -f $tempDir/*.gz`;
 | 
        
           |  |  | 170 |   | 
        
           |  |  | 171 | }
 | 
        
           |  |  | 172 |   | 
        
           |  |  | 173 | sub getDeviceID {
 | 
        
           |  |  | 174 |    my $device = shift;
 | 
        
           |  |  | 175 |    $device = &GenericSQL::fixStringValue($dbh, $device);
 | 
        
           |  |  | 176 |    my $sql = "select distinct device_id from device where name = $device union select device_id from device_alias where alias = $device";
 | 
        
           |  |  | 177 |    #print "\t$sql\n";
 | 
        
           |  |  | 178 |    #return 1;
 | 
        
           |  |  | 179 |    return &GenericSQL::getOneValue($dbh,$sql);
 | 
        
           |  |  | 180 | }
 | 
        
           |  |  | 181 |   | 
        
           |  |  | 182 | sub parseFileName {
 | 
        
           |  |  | 183 |    my $fileName = shift;
 | 
        
           |  |  | 184 |    $fileName =~ m/(\d+)_(.+)\.backup\.log/;
 | 
        
           |  |  | 185 |    return (&getDeviceID($2),$2,$1);
 | 
        
           |  |  | 186 | }
 | 
        
           |  |  | 187 |   | 
        
           |  |  | 188 |   | 
        
           |  |  | 189 | ###############################################################################
 | 
        
           |  |  | 190 | #            BEGIN MAIN ROUTINE
 | 
        
           |  |  | 191 | ###############################################################################
 | 
        
           |  |  | 192 |   | 
        
           |  |  | 193 | BEGIN{
 | 
        
           |  |  | 194 |    # load the configuration file
 | 
        
           |  |  | 195 |    eval ( &loadConfigurationFile );
 | 
        
           |  |  | 196 |    push @INC, $LIBRARIES;
 | 
        
           |  |  | 197 | }
 | 
        
           |  |  | 198 |   | 
        
           |  |  | 199 | use strict;
 | 
        
           |  |  | 200 | no strict 'vars';
 | 
        
           |  |  | 201 | use Data::Dumper;
 | 
        
           |  |  | 202 | use GenericSQL; # generic, home grown MySQL access routines
 | 
        
           |  |  | 203 | #use GenericTemplates;
 | 
        
           |  |  | 204 | use Logging; # generic, home grown logging routines
 | 
        
           |  |  | 205 | use Date::Format; # allows us to format our dates nicely
 | 
        
           |  |  | 206 | use Date::Parse; # VERY KEWL, parses out a huge number of date formats
 | 
        
           |  |  | 207 |   | 
        
           |  |  | 208 | $dbh = DBI->connect( $DSN, $DB_USER , $DB_PASS ) or die $DBI::errstr; # try to connect to db first
 | 
        
           |  |  | 209 |   | 
        
           |  |  | 210 |   | 
        
           |  |  | 211 | &getAttachments; # unpacks all attachments into $tempDir and gunzips them
 | 
        
           |  |  | 212 | # now, process each file in turn
 | 
        
           |  |  | 213 | opendir (DATADIR,$tempDir)  || die "can't opendir $tempDir: $!"; # read the directory
 | 
        
           |  |  | 214 | while ( my $thisFile = readdir(DATADIR) ) { # for each file
 | 
        
           |  |  | 215 |    next if $thisFile =~ m/^\./; # skip if it is a "dot" file
 | 
        
           |  |  | 216 |    print "It is not a dot file\n" if $TESTING >= 3;
 | 
        
           |  |  | 217 |    next unless -f "$tempDir/$thisFile";
 | 
        
           |  |  | 218 |    print "Looking at $thisFile\n" if $TESTING >= 2;
 | 
        
           |  |  | 219 |    ($device_id,$device,$report_date) = &parseFileName($thisFile);
 | 
        
           |  |  | 220 |    print "\tparseFileName = Device: $device_id Date:$report_date\n" if $TESTING >= 2;
 | 
        
           |  |  | 221 |    unless ( $device_id ) {
 | 
        
           |  |  | 222 |       push @errors, "Could not find device info on $thisFile";
 | 
        
           |  |  | 223 |       next;
 | 
        
           |  |  | 224 |    }
 | 
        
           |  |  | 225 |    unless ( $report_date ) {
 | 
        
           |  |  | 226 |       push @errors, "Invalid report date for $thisFile";
 | 
        
           |  |  | 227 |       next;
 | 
        
           |  |  | 228 |    }
 | 
        
           |  |  | 229 |    if ( exists( $backupDomains{ $device } ) ) {
 | 
        
           |  |  | 230 |       $backupDomains{ $device } = 1;
 | 
        
           |  |  | 231 |    } else {
 | 
        
           |  |  | 232 |       push @errors, "$device not created in backups to process, processing anyway";
 | 
        
           |  |  | 233 |    } 
 | 
        
           |  |  | 234 |    print "\tDevice: $device_id\tDate: $report_date\n" if $TESTING;
 | 
        
           |  |  | 235 |    # check for duplicate report
 | 
        
           |  |  | 236 |    next if &GenericSQL::getOneValue($dbh,qq/select count(*) from backups_run join backups using (backups_id) where device_id = $device_id and report_date = '$reportDate'/);
 | 
        
           |  |  | 237 |    $sql = &processFile($tempDir . '/' . $thisFile, $device_id,$report_date);
 | 
        
           |  |  | 238 |    # if no sql returned, it is not a valid file
 | 
        
           |  |  | 239 |    unless ( $sql ) {
 | 
        
           |  |  | 240 |       push @errors, "Could not generate SQL statement for $thisFile";
 | 
        
           |  |  | 241 |       next;
 | 
        
           |  |  | 242 |    }
 | 
        
           |  |  | 243 |    unlink "$tempDir/$thisFile";
 | 
        
           |  |  | 244 |    print "$sql\n" if $TESTING >= 3;
 | 
        
           |  |  | 245 |    &GenericSQL::doSQL( $dbh,$sql );
 | 
        
           |  |  | 246 | }
 | 
        
           |  |  | 247 | closedir(DATADIR);
 | 
        
           |  |  | 248 |   | 
        
           |  |  | 249 | foreach my $temp ( keys %backupDomains ) {
 | 
        
           |  |  | 250 |    push @errors, "No backup for $temp" unless $backupDomains{$temp};
 | 
        
           |  |  | 251 | }
 | 
        
           |  |  | 252 |   | 
        
           |  |  | 253 | if ( @errors ) {
 | 
        
           |  |  | 254 |   print "ERRORS DETECTED:\n" . join( "\n", @errors ) . "\n";
 | 
        
           |  |  | 255 |   my $message = "Subject: ERRORS on backups\n\n" . join( "\n", @errors ) . "\n";
 | 
        
           |  |  | 256 |   open SENDMAIL, "|$SENDMAIL" or die "Can not open $SENDMAIL: $!\n";
 | 
        
           |  |  | 257 |   print SENDMAIL "To: $MISSING_BACKUP_MAILTO\n";
 | 
        
           |  |  | 258 |   print SENDMAIL $message;
 | 
        
           |  |  | 259 |   close SENDMAIL;
 | 
        
           |  |  | 260 | }
 | 
        
           |  |  | 261 | 1;
 |