Do you also use mail to “report” back on succesfull bash backup scripts running all over your enterprise? The “Backup” mailbox is flushed each day ending up being deleted instead of being checked?
Well for all people in that situation I have written a very basic but functional “Monitoring” script written in PHP. It is not finished yet (needs refinement) and your free to extend it as you see fit.
What does it look like? (yes it needs to be graphical! )
How does it work?
- copy the php scripts into an php enable webserver (wamp / apache & php / iis & php )
- create a directory ‘data’ in the directory where the index.php is located.
- call the script using any commandline webclient (example using wget (linux))
Generate an post file containing the post data, this can be done in a script using some creativity
echo “ok=hostname.domain.ext&msgs=all_backup_messages\n newline seperated” > ./post
Use wget and the generated post file to call the script.
wget -q –post-file ./post http://apache_php.hostname.ext/backup/index.php –output-document /dev/null - Logon to the backup script to view the state.
Possible calls?
index.php?ok=[hostname]
index.php?err=[hostname]
index.php?warn=[hostname]
index.php?debug=true
index.php?msgs=[all messages \n is translated to <br> automatically]
Example call
http://127.0.0.1/index.php?ok=localhost.localdomain.org&msgs=all accumilated messages \n new line messages \n finished..
The application exists out of following files…
// Here is the sourcecode needed to get it all working //
// Please dont be too harsh, the code NEEDS MORE WORK //
// ITS CONSEPTUAL, BUT FUNCTIONAL. TIPS? PLZ POST //
// HINTS? PLZ POST, BASHING move on //
Good luck…
<?php // Script by chris, written to track backup scripts over the network... ///// include('subcsv.php'); // Global vars being declared. $err = false; // We start without any errors (duh) $errmsg = array(); // The error message array is empty $datadir='./data/'; // Where do we store our reported data? $view=false; // At first we dont want to view the data // check if any of the required vars was used // // If no instructions (gets) (registering) where send we simply show the // recorded data. (reporting) if(isset($_GET['ok']) || isset($_GET['warn']) || isset($_GET['err']) || isset($_POST['ok']) || isset($_POST['err']) || isset($_POST['warn'])){ //////// CATCH A POTENTIAL OK /////////// if(isset($_POST['ok']) || isset($_GET['ok'])){ if((strlen($_POST['ok']) > 3 ) || (strlen($_GET['ok']) > 3)){ $host['ok'] = (isset($_POST['ok'])) ? $_POST['ok'] : $_GET['ok']; }else{ $err = true; $errmsg[] = 'Reported hostname to short!'; } }else{ $host['ok'] = false; } //////// CATCH A POTENTIAL WARN /////////// if(isset($_POST['warn']) || isset($_GET['warn'])){ if((strlen($_POST['warn']) > 3 ) || (strlen($_GET['warn']) > 3)){ $host['warn'] = (isset($_POST['warn'])) ? $_POST['warn'] : $_GET['warn']; }else{ $err = true; $errmsg[] = 'Reported hostname to short!'; } }else{ $host['warn'] = false; } //////// CATCH A POTENTIAL ERROR /////////// if(isset($_POST['err']) || isset($_GET['err'])){ if((strlen($_POST['err']) > 3 ) || (strlen($_GET['err']) > 3)){ $host['ok'] = (isset($_POST['ok'])) ? $_POST['err'] : $_GET['err']; }else{ $err = true; $errmsg[] = 'Reported hostname to short!'; } }else{ $host['error'] = false; } //////// VIEW Debugging? /////////// if(isset($_GET['debug'])){$debug = true;}else{$debug = false;} }else{ // if we have no instructions (gets) show the report. $view = true; } // CATCH POTENTIAL MESSAGE(S) (intended for the backup log ;-) // if(isset($_POST['msgs']) || isset($_GET['msgs'])){ $msgs=(isset($_POST['msgs'])) ? $_POST['msgs'] : $_GET['msgs']; }else{ $msgs=''; } // Start the functional part :) // if(!$err){ if($view){ // Load the HTML header require_once('view_tmpl.php'); // Fetch the files from the data dir // If any? // if($content = opendir($datadir)){ // Global counter $gc = 1; // Read the directory contents while($item = readdir($content)){ if(strstr($item, '.bak' )){ if(is_file($datadir.$item)){ // Clear the data array $data = ''; if($fp = fopen($datadir.$item, 'r')){ while($line = fgets($fp)){ $data[] = $line; if($debug){print_r($data);} } }else{ print('false'); } }else{ echo 'open failed?'; } // how much entries does this backup have? $n = 0; $n = count($data); // find the last index $l = $n - 1; // restore the data $entities = str_getcsv_cust($data[0], ';'); if($debug){var_dump($entities);} $first_backup = $entities[0][0]; $entities = str_getcsv_cust($data[$l], ';'); // Get the current days of year $cdate = getdate(); // Compare the date of the last registration // with the current day of year. $fdate = getdate(strtotime($entities[0][0])); $diff = $cdate['yday'] - $fdate['yday']; // Validate entities[3] (reported status) // if($entities[0]['3'] == 'ok'){$c1="<td bgcolor='green'>{$entities[0]['4']}</td><td bgcolor='green'>{$entities[0]['3']}</td>"; }elseif($entities[0]['3'] == 'err'){$c1="<td bgcolor='yellow'>{$entities[0]['4']}</td><td bgcolor='yellow'>{$entities[0]['3']}</td>"; }else{$c1="<td bgcolor='red'>{$entities[0]['4']}</td><td bgcolor='red'>{$entities[0]['3']}</td>";} // Validate the date difference // if($diff > 1){ $c2="<td bgcolor='red'>{$entities[0]['0']}</td>"; }else{ $c2="<td bgcolor='green'>{$entities[0]['0']}</td>"; } // Convert the backup msg so the \n are converted to a readable message(s) $bmsg = nl2br($entities[0]['5']); $bmsg = str_replace('\n', '<br/>', $bmsg); $bmsg = str_replace('\r', '', $bmsg); // Print the validated row... print("<tr><td><div id='links'><a href='#'>$gc<span><table class='tooltip'width='100%' align='right' cellspacing='0'><tr><th>Backup messages</th></tr><tr><td><div align='left' style='padding-left:5px;'>$bmsg<br/><br/></div></td></tr></table></span></a></div></td> $c1$c2<td>{$entities[0]['1']}</td><td>$first_backup</td><td>$n</td></tr>"); // Up the global counter :) $gc++; #print($diff); #print_r($entities); } } }else{ print('no backups registered "YET" ;-)'); } // Close the table // print('</table>'); }else{ // We are saving an backup state, register this request! // if(is_array($host)){ // Is this host allowed? // include('allowed_hosts.php'); // Itterate through a single entry :) foreach($host as $k => $v){ // Collect some random but usefull information about this registration $rip=$_SERVER['REMOTE_ADDR']; $time=date('H:i:s'); $date=date('d-m-Y'); $file=$datadir.$v.".bak"; // Is this host allowed? //if(in_array($v, $allowed_hosts)){ // Sometimes array indexes are predefined during script load, so filter these out :) // if(!empty($host[$k])){ // If the file doesnt exist create it :) // if(!is_file($file)){ touch($file); } if($fp = fopen($file, 'a')){ $csv = "$date;$time;$rip;$k;$v;$msgs"; if(fwrite($fp, $csv)){ print('true <br>'); exit; }else{ print('false'); exit; } } // Debugging are we? if($debug){ print("$k > $v <br>\r\n"); print_r($msgs); } } //}else{ // print($_GET['ok']); // die('your host isnt allowed in the allowed_hosts yet!'); //} } }else{ die('invalid instruction received!'); } } }else{ print_r($errmsg); } ?>
//SUBCSV.PHP <?php #if (!function_exists('str_getcsv')) { function str_getcsv_cust($input, $delimiter = ',', $enclosure = '"', $escape = '\\', $eol = '\n') { if (is_string($input) && !empty($input)) { $output = array(); $tmp = preg_split("/".$eol."/",$input); if (is_array($tmp) && !empty($tmp)) { while (list($line_num, $line) = each($tmp)) { if (preg_match("/".$escape.$enclosure."/",$line)) { while ($strlen = strlen($line)) { $pos_delimiter = strpos($line,$delimiter); $pos_enclosure_start = strpos($line,$enclosure); if ( is_int($pos_delimiter) && is_int($pos_enclosure_start) && ($pos_enclosure_start < $pos_delimiter) ) { $enclosed_str = substr($line,1); $pos_enclosure_end = strpos($enclosed_str,$enclosure); $enclosed_str = substr($enclosed_str,0,$pos_enclosure_end); $output[$line_num][] = $enclosed_str; $offset = $pos_enclosure_end+3; } else { if (empty($pos_delimiter) && empty($pos_enclosure_start)) { $output[$line_num][] = substr($line,0); $offset = strlen($line); } else { $output[$line_num][] = substr($line,0,$pos_delimiter); $offset = ( !empty($pos_enclosure_start) && ($pos_enclosure_start < $pos_delimiter) ) ?$pos_enclosure_start :$pos_delimiter+1; } } $line = substr($line,$offset); } } else { $line = preg_split("/".$delimiter."/",$line); /* * Validating against pesky extra line breaks creating false rows. */ if (is_array($line) && !empty($line[0])) { $output[$line_num] = $line; } } } return $output; } else { return false; } } else { return false; } } #} ?>
// VIEW_TMPL.PHP <?php // File for the view html // HEAD print(' <!doctype html> <html> <head> <meta http-equiv="refresh" content="30"> <meta http-equiv="X-UA-Compatible" content="IE=8"> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <title>Backup status</title> <style> table{ border-top:1px solid #000; border-right:1px solid #000; } table th{ font-family:verdana; font-size:12px; font-weight:bold; border-left:1px solid #000; border-bottom:1px solid #000; background-color:#CCC; } table td{ text-align:center; font-family:verdana; font-size:10px; border-left:1px solid #000; border-bottom:1px solid #000; } a:link{ display:block; position:relative; z-index:10; height:100%; width:100%; text-decoration:none; } a:visited{ display:block; position:relative; z-index:10; height:100%; width:100%; text-decoration:none; } div#links div{ position:static; z-index:10; } div#links a:hover span {display: block; position: absolute; top: 0px; left: 50px; width: 700px; padding: 5px; margin: 10px; z-index: 100; color: #222; background: #EEE; font: 10px Verdana, sans-serif; text-align: center; border: 1px solid #000; } div#links a span {display: none;} table tr:hover{ background-color:#CCC; cursor:hand; } p{ font-family:verdana; font-size:10px; } .tooltip table td{ align:left; } </style> </head> <body> '); // Start the Backup list // Create a nice table print(' <table cellspacing="0" cellpadding="2" width="90%"> <tr><td colspan="7"><p>insert a new backup by calling this script using the following url<br> '.$_SERVER['PHP_SELF'].'?{ok|err|warn}={hostname}&msgs={backup log \n seperated}<br/><br /> download an example bash script <a href="/backup/download/">here<a/> </p></td></tr> <tr> <th>N</th> <th>Hostname</th> <th>State</th> <th>Date Last</th> <th>Time Last</th> <th>Date First Ever</th> <th># in file</th> </tr>'); ?>
