Rev 94 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
<?php
/*
* Requires php-pear and libyaml under Debian Wheezy
*
* apt-get install php-pear php5-dev libyaml-dev libyaml-0-2 libyaml-0-2-dbg
* pecl install yaml
* echo 'extension=yaml.so' >> /etc/php5/cli/php.ini
* echo 'extension=yaml.so' >> /etc/apache2/cli/php.ini
*
* truncate table backups_run
* alter table backups_run add skipped bigint(20),add file_name varchar(60),add notes text;
* alter table backups_run modify end_time datetime null, modify start_time datetime null;
* alter table backups_run add added_date datetime not null;
*
* Version 0.1.1 20160713 RWR
* Fixed issue where report had no transfers. In that case, header lines
* are terminated by two blank lines, not the constant 'sending incremental file
* list'. Simply modified to terminate on an empty line OR the constant
*
* Also set it up to only report on one file at a time, ie accept
* only one parameter, and that is assumed to be a file name
*
* Version 0.2.0 20160826 RWR
* Fixed problem where file name has YYYYMMDD_HHMMSS_servername_backup.log instead of
* YYYYMMDD_servername_backup.log (it now checks for both)
* Start and end time now accepted as YYYYMMDD_HHMMSS or YYYYMMDDHHMMSS
*
* Version 0.2.1 20191208 RWR
* When numeric strings are looked for, allow comma's in them and remove them before recording in the database
* Fixes modifications made to rsync where reports now contain comma's.
*/
/*
* This will return error codes
* 1 - Invalid Data File Name
* 2 - Could not open the file
* 3 - Duplicate Report
* 4 - Server Not Found
*/
require 'library.php';
$VERSION='0.2.1';
$results = array();
function parseFile( $filename, $path, $maxLineLength = 4096 ) {
$data = array (
'server_name' => '',
'report_date' => '',
'start_time' => '',
'version' => '',
'end_time' => '',
'files_count' => 0,
'files_size' => 0,
'transferred_count' => 0,
'transferred_size' => 0,
'files_deleted' => 0,
'skipped' => 0,
'data_sent' => 0,
'data_received' => 0,
'disk_used' => '',
'notes' => '',
);
function cleanNumber( $number ) {
return preg_replace("/[^0-9.]/", "", $number );
}
$matches = array();
$line;
$data['file_name'] = $filename;
# get server name from the file name, which should be
# date_time_servername.backup.log
if ( preg_match( '/(\d+)_(\d+)_([a-z0-9_.-]+)\.backup\.log/', $filename, $matches ) ) {
$data['report_date'] = $matches[1] . $matches[2];
$data['server_name'] = $matches[3];
} elseif ( preg_match( '/(\d+)_([a-z0-9_.-]+)\.backup\.log/', $filename, $matches ) ) {
# datetime_servername.backup.log
$data['report_date'] = $matches[1];
$data['server_name'] = $matches[2];
} else {
# ensure only three parts returned
$data['error'] = "1\tInvalid Data File Name";
return $data;
}
$log = fopen ( $path . '/' . $filename , 'rb' );
if ( $log ) {
// get through the header lines, ended by either a blank line
// or the constant 'sending incremental file list'
while (( $line = fgets( $log, $maxLineLength )) !== false ) {
$line = rtrim( $line );
if ( $line ) {
if ( preg_match( '/^backup\s+v?([\d.]+)$/', $line, $matches ) ) {
$data['version'] = $matches[1];
}
// this line is the end of the header lines
if ( preg_match( '/sending incremental file list/', $line, $matches ) ) {
break;
}
} else {
break;
}
}
// count line by line processing information. These are the actual lines
// indicating files checked and how they were processed
while (( $line = fgets( $log, $maxLineLength )) !== false ) {
$line = rtrim($line);
if ( $line ) {
if ( ! preg_match( '~/$~', $line ) ) // count lines not ending in /, ie not directories
$data['transferred_count']++;
if ( preg_match( '/^deleting /', $line ) ) // count number deleted
$data['files_deleted']++;
if ( preg_match( '/^skipping /', $line ) ) // count number skipped
$data['skipped']++ ;
} else {
break;
}
}
$data['transferred_count'] -= $data['files_deleted'] + $data['skipped'];
// we should have a stats summary at the end
while (( $line = fgets( $log, $maxLineLength )) !== false ) {
$data['notes'] .= $line; // everything here goes into notes
if ( preg_match( '/Number of files:\s+([0-9,]+)/', $line, $matches ) ) {
$data['files_count'] = cleanNumber($matches[1]);
} elseif ( preg_match( '/Number of files transferred:\s+([0-9,]+)/', $line, $matches ) ) {
$data['transferred_count'] = cleanNumber($matches[1]);
} elseif ( preg_match( '/Total file size:\s+([0-9,]+) bytes/', $line, $matches ) ) {
$data['files_size'] = cleanNumber($matches[1]);
} elseif ( preg_match( '/Total transferred file size:\s+([0-9,]+) bytes/', $line, $matches ) ) {
$data['transferred_size'] = cleanNumber($matches[1]);
} elseif ( preg_match( '/Total bytes sent:\s+([0-9,]+)/', $line, $matches ) ) {
$data['data_sent'] = cleanNumber($matches[1]);
} elseif ( preg_match( '/Total bytes received:\s+([0-9,]+)/', $line, $matches ) ) {
$data['data_received'] = cleanNumber($matches[1]);
} elseif ( preg_match( '/Backup Version\s+v?([\d.]+)/', $line, $matches ) ) {
// this is the end of the rsync stats summary, and the
// beginning of the rsbackup summary
$data['version'] = $matches[1];
break;
}
}
// process rsbackup summary
while (( $line = fgets( $log, $maxLineLength )) !== false ) {
$data['notes'] .= $line;
if ( preg_match( '/^Begin\s+([\d_]+)/', $line, $matches ) ) {
$data['start_time'] = str_replace( '_', '', $matches[1] );
} elseif ( preg_match( '/Complete\s+([\d_]+)/', $line, $matches ) ) {
$data['end_time'] = str_replace( '_', '', $matches[1] );
} elseif ( preg_match( '/^Status:/', $line, $matches ) ) {
break;
}
}
// the rest of it just goes into notes
while (( $line = fgets( $log, $maxLineLength )) !== false ) {
$data['notes'] .= $line;
}
fclose ( $log );
} else {
$data['error'] = "2\tCould not open file name $filename for read";
}
return $data;
}
function recordMessage( $message ) {
global $results;
$results[] = $message;
}
/*
* checks for a duplicate report, ie one that has already been run.q
* if this computer has a report already for this date/time
*/
function checkDuplicate( $backups_id, $report_date) {
$sql = "select count(*) from backups_run where backups_id = $backups_id and report_date = $report_date";
$count = getOneDBValue( $sql );
return $count ? "3\tDuplicate Report for $backups_id on $report_date" : null;
} // recordReport
function findServer( $name ) {
$sql = "select distinct( device_id ) from (select device_id from device where name = '$name' union select device_id from device_alias where alias = '$name') a";
$device_id = getOneDBValue( $sql );
if ( ! isset( $device_id ) ) {
recordMessage( "Could not locate device $name, not processing record" );
return null;
}
$sql = "select backups_id from backups where device_id = $device_id";
$backups_id = getOneDBValue( $sql );
if ( isset( $backups_id ) ) {
return $backups_id;
} else {
recordMessage( "Adding server $name to backups" );
$sql = "insert into backups ( device_id,backups_server_id,notes ) values ( $device_id, 1, 'Automatically Added' )";
$results = queryDatabaseExtended( $sql );
return $results['insert_id'];
}
}
/*
* Creates an entry in the backups_run table
*/
function recordReport( $report ) {
$keys = array();
$values = array();
foreach ( $report as $keyfield => $value ) {
if ( $keyfield == 'server_name' ) {
$keys[] = 'backups_id';
$device_id = findServer( $value );
if ( isset( $device_id ) ) {
$values[] = $device_id;
$duplicate = checkDuplicate( $device_id, $report['report_date'] );
if ( $duplicate )
return $report['file_name'] . "\t$duplicate";
} else {
return $report['file_name'] . "\t4\tServer not found";
}
} else {
$keys[] = $keyfield;
$values[] = makeSafeSQLValue( $value );
}
}
$keys[] = 'added_date'; $values[] = 'now()';
$sql = 'insert into backups_run (' . implode( ',', $keys ) . ') values (' . implode( ',', $values ) . ')';
// if we made it this far, we are ok, so just add the report id
$result = queryDatabaseExtended( $sql );
return $report['file_name'] . "\t0\tok";
} // recordReport
/*
* we don't know where the configuration file will be, so we have a list
* below (searchPaths) to look for it. It will load the first one it
* finds, then exit. THUS, you could have multiple configuration files
* but only the first one in the list will be used
*/
$confFileName = "rsbackupRead.conf.yaml";
$searchPaths = array( '/etc/camp', '/opt/camp', '/opt/camp/rsbackup', $_SERVER['SCRIPT_FILENAME'], getcwd() );
$configuration = array();
foreach ( $searchPaths as $path ) {
if ( file_exists( "$path/$confFileName" ) ) {
$configuration = yaml_parse_file( "$path/$confFileName" );
break; // exit out of the loop; we don't try to load it more than once
} // if
} // foreach
mysql_connect( $configuration['database']['databaseServer'], $configuration['database']['databaseUsername'], $configuration['database']['databasePassword'] ) or die(mysql_error());
mysql_select_db( $configuration['database']['database'] ) or die(mysql_error());
$filename = $argv[1];
$report = parseFile( $filename, $configuration['datapath'] . '/' . $configuration['unprocessed_path'] );
# print_r( $report ); print "\n";
if ( isset( $report['error'] ) ) { // we had an error processing the report
$result[] = "$filename\t" . $report['error'];
} else {
$result[] = recordReport( $report );
}
print implode( "\n", $result );
?>