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;
|