3 +-------------------------------------------------------------------------+
4 | Copyright (C) 2004 Juan Luis Francés Jiménez |
5 | Copyright 2010-2011, Davide Franco |
7 | This program is free software; you can redistribute it and/or |
8 | modify it under the terms of the GNU General Public License |
9 | as published by the Free Software Foundation; either version 2 |
10 | of the License, or (at your option) any later version. |
12 | This program is distributed in the hope that it will be useful, |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | GNU General Public License for more details. |
16 +-------------------------------------------------------------------------+
23 public $db_link; // Database link
25 private $config_file; // Config filename
26 private $config; // Loaded config from bacula.conf
27 private $catalogs = array(); // Catalog array
31 function __construct()
33 $this->bwcfg = new Config();
36 // Loading configuration from config file
37 $this->bwcfg->Load_Config();
38 $this->catalog_nb = $this->bwcfg->Count_Catalogs();
40 // Select which catalog to connect to
41 if( isset( $_POST['catalog_id'] ) )
42 $dsn = $this->bwcfg->Get_Dsn( $_POST['catalog_id'] );
44 $dsn = $this->bwcfg->Get_Dsn( 0 );
46 // Connect to the database
47 $options = array( 'portability' => DB_PORTABILITY_ALL );
48 $this->db_link = $this->connect( $dsn, $options );
50 if (DB::isError($this->db_link)) {
51 die( 'Unable to connect to catalog <br />' . $this->db_link->getMessage());
53 $this->driver = $dsn['phptype'];
54 register_shutdown_function(array(&$this,'close') );
55 $this->db_link->setFetchMode(DB_FETCHMODE_ASSOC);
58 // Initialize smarty template classe
60 // Initialize smarty gettext function
61 $this->init_gettext();
64 if( $this->catalog_nb > 1 ) {
65 // Set current catalog in header template
66 if(isset( $_POST['catalog_id'] ) )
67 $this->tpl->assign( 'catalog_current', $_POST['catalog_id'] );
69 $this->tpl->assign( 'catalogs', $this->bwcfg->Get_Catalogs() );
73 // Initialize Smarty template classe
76 $this->tpl = new Smarty();
78 $this->tpl->compile_check = true;
79 $this->tpl->debugging = false;
80 $this->tpl->force_compile = true;
82 $this->tpl->template_dir = "./templates";
83 $this->tpl->compile_dir = "./templates_c";
84 $this->tpl->config_dir = "./configs";
87 function init_gettext()
89 global $smarty_gettext_path;
91 if ( function_exists("gettext") ) {
92 require_once( BW_SMARTY_GETTEXT . "smarty_gettext.php" );
93 $this->tpl->register_block('t','smarty_translate');
95 $language = $this->bwcfg->Get_Config_Param("lang");
97 putenv("LANG=$language");
98 setlocale(LC_ALL, $language);
99 bindtextdomain($domain,"./locale");
103 function smarty_translate($params, $text, &$smarty) {
106 $smarty->register_block('t','smarty_translate');
112 $this->db_link->disconnect();
120 switch( $this->driver )
123 $query = "SELECT table_schema AS 'database', sum( data_length + index_length) AS 'dbsize' ";
124 $query .= "FROM information_schema.TABLES ";
125 $query .= "WHERE table_schema = 'bacula' ";
126 $query .= "GROUP BY table_schema";
129 $query = "SELECT pg_database_size('bacula') AS dbsize";
132 // Not yet implemented
137 $result = $this->db_link->query( $query );
139 if(! PEAR::isError( $result ) )
141 $db = $result->fetchRow( DB_FETCHMODE_ASSOC );
142 $database_size = $db['dbsize'];
144 die( "Unable to get database size<br />" . $result->getMessage() );
146 return CUtils::Get_Human_Size( $database_size );
147 } // end function GetDbSize()
149 public function Get_Nb_Clients()
151 $clients = $this->db_link->query("SELECT COUNT(*) AS nb_client FROM Client");
152 if( PEAR::isError($clients) )
153 die( "Unable to get client number" );
155 return $clients->fetchRow( DB_FETCHMODE_ASSOC );
158 // Return an array of volumes ordered by poolid and volume name
159 function GetVolumeList() {
165 // Get the list of pools id
166 $query = "SELECT Pool.poolid, Pool.name FROM Pool ORDER BY Pool.poolid";
168 //$this->db_link->setFetchMode(DB_FETCHMODE_ASSOC);
169 $pools = $this->db_link->query( $query );
171 if( PEAR::isError( $pools ) )
172 die("Error: Failed to get pool list <br />SQL Query: $query<br />" . $pools->getMessage() );
174 while( $pool = $pools->fetchRow( DB_FETCHMODE_ASSOC ) ) {
175 switch( $this->driver )
178 $query = "SELECT Media.volumename, Media.volbytes, Media.volstatus, Media.mediatype, Media.lastwritten, Media.volretention
179 FROM Media LEFT JOIN Pool ON Media.poolid = Pool.poolid
180 WHERE Media.poolid = '". $pool['poolid'] . "' ORDER BY Media.volumename";
183 $query = "SELECT media.volumename, media.volbytes, media.volstatus, media.mediatype, media.lastwritten, media.volretention
184 FROM media LEFT JOIN pool ON media.poolid = pool.poolid
185 WHERE media.poolid = '". $pool['poolid'] . "' ORDER BY media.volumename";
188 $query = ""; // not yet implemented
194 $medias = $this->db_link->query( $query );
196 if( PEAR::isError( $medias ) ) {
197 die( "Failed to get media list for pool $volume[0] <br /> " . $medias->getMessage() );
199 if( $debug ) echo "Found " . $medias->numRows() . " medias for pool " . $pool['name'] . " <br />";
201 // Create array key for each pool
202 if( !array_key_exists( $pool['name'], $volumes) )
204 $volumes[ $pool['name'] ] = array();
206 while( $media = $medias->fetchRow( DB_FETCHMODE_ASSOC ) ) {
210 // If the pool is empty (no volumes in this pool)
211 if( $medias->numRows() == 0 ) {
212 if( $debug ) echo "No media in pool " . $pool['name'] . "<br />";
214 if( $media['lastwritten'] != "0000-00-00 00:00:00" ) {
215 // Calculate expiration date if the volume is Full
216 if( $media['volstatus'] == 'Full' ) {
217 $expire_date = strtotime($media['lastwritten']) + $media['volretention'];
218 $media['expire'] = strftime("%Y-%m-%d", $expire_date);
220 $media['expire'] = 'N/A';
222 // Media used bytes in a human format
223 $media['volbytes'] = CUtils::Get_Human_Size( $media['volbytes'] );
225 $media['lastwritten'] = "N/A";
226 $media['expire'] = "N/A";
227 $media['volbytes'] = "0 KB";
231 if( count( $volumes[ $pool['name'] ] ) % 2)
232 $media['class'] = 'odd';
234 // Add the media in pool array
235 array_push( $volumes[ $pool['name']], $media);
241 } // end function GetVolumeList()
243 public function CountJobsbyLevel( $delay = LAST_DAY, $level = 'F' )
245 $end_date = mktime();
246 $start_date = $end_date - $delay;
248 $start_date = date( "Y-m-d H:i:s", $start_date );
249 $end_date = date( "Y-m-d H:i:s", $end_date );
251 $query = "SELECT COUNT(JobId) as jobs FROM Job ";
252 $query .= "WHERE (EndTime BETWEEN '$start_date' AND '$end_date') AND ";
253 $query .= "Level = '$level' ";
255 $result = $this->db_link->query( $query );
257 if (PEAR::isError( $result ) ) {
258 die( "Unable to get number of jobs with $level status from catalog <br />" . $result->getMessage() );
260 $jobs = $result->fetchRow( DB_FETCHMODE_ASSOC );
261 return $jobs['jobs'];
266 public function CountJobs( $delay = LAST_DAY, $status = 'any' )
268 $query = "SELECT COUNT(JobId) AS job_nb FROM Job ";
272 // Interval condition for SQL query
273 if( $delay != ALL ) {
274 $end_date = mktime();
275 $start_date = $end_date - $delay;
277 $start_date = date( "Y-m-d H:i:s", $start_date );
278 $end_date = date( "Y-m-d H:i:s", $end_date );
280 $where_delay = "WHERE EndTime BETWEEN '$start_date' AND '$end_date' ";
283 if( $status != 'any' ) {
287 $where_status = "JobStatus = 'T' ";
290 $where_status = "JobStatus IN ('f','E') ";
293 $where_status = "JobStatus = 'A' ";
296 $where_status = "JobStatus IN ('F','S','M','m','s','j','c','d','t') ";
301 if( !empty($where_delay) )
302 $query = $query . $where_delay . 'AND ' . $where_status;
304 if( !empty($where_status) )
305 $query = $query . 'WHERE ' . $where_status;
308 $jobs = $this->db_link->query( $query );
310 if (PEAR::isError( $jobs ) ) {
311 die( "Unable to get last $status jobs number from catalog <br />" . $jobs->getMessage() );
313 $jobs = $jobs->fetchRow( DB_FETCHMODE_ASSOC );
314 return $jobs['job_nb'];
318 // Return the list of Pools in a array
319 public function Get_Pools_List()
322 $query = "SELECT Name, PoolId FROM Pool";
323 $result = $this->db_link->query ( $query );
325 if( PEAR::isError( $result ) ) {
326 $this->TriggerDBError( "Unable to get the pool list from catalog", $result );
332 public function Get_BackupJob_Names()
334 $query = "SELECT job.name FROM job GROUP BY job.name";
335 $backupjobs = array();
337 $result = $this->db_link->query( $query );
339 if (PEAR::isError( $result ) ) {
340 $this->TriggerDBError("Unable to get BackupJobs list from catalog", $result );
342 while( $backupjob = $result->fetchRow() ) {
343 array_push( $backupjobs, $backupjob["name"] );
349 // Return Jobs statistics for a specific interval such as
350 // - Completed jobs number
351 // - Failed jobs number
352 // - Waiting jobs number
353 // The returned values will be used by a Bgraph classe
354 public function GetJobsStatistics( $type = 'completed', $delay = LAST_DAY )
362 // Interval calculation
363 $end_date = mktime();
364 $start_date = $end_date - $delay;
366 $start_date = date( "Y-m-d H:i:s", $start_date );
367 $end_date = date( "Y-m-d H:i:s", $end_date );
369 $interval_where = "(EndTime BETWEEN '$start_date' AND '$end_date') AND ";
375 $where = $interval_where . "JobStatus = 'T' ";
376 $label = "Completed";
378 case 'terminated_errors':
379 $where = $interval_where . "JobStatus = 'E' ";
380 $label = "Terminated with errors";
383 $where = $interval_where . "JobStatus = 'f' ";
387 $where = "JobStatus IN ('F','S','M','m','s','j','c','d','t') ";
391 $where = "JobStatus = 'C' ";
392 $label = "Created but not running";
395 $where = "JobStatus = 'R' ";
399 $where = $interval_where . "JobStatus IN ('e','f') ";
404 $query = 'SELECT COUNT(JobId) AS ' . $type . ' ';
405 $query .= 'FROM Job ';
406 $query .= "WHERE $where ";
408 //echo 'query = ' . $query . '<br />';
410 $jobs = $this->db_link->query( $query );
412 if (PEAR::isError( $jobs ) ) {
413 die( "Unable to get last $type jobs status from catalog<br />" . $status->getMessage() );
415 $res = $jobs->fetchRow();
416 return array( $label , current($res) );
418 } // end function GetJobsStatistics()
420 public function CountVolumesByPool( $pool_id )
422 var_dump( $pool_id );
425 $query = "SELECT COUNT(*) as nb_vol FROM media WHERE poolid = $pool_id";
427 $res = $this->db_link->query( $query );
428 if( PEAR::isError( $res ) )
429 $this->triggerDBError( 'Unable to get volume number from pool', $res );
431 $nb_vol = $res->fetchRow( );
433 return array( $pool_name, $nb_vol['nb_vol'] );
436 public function GetStoredFiles( $delay = LAST_DAY )
440 $query = "SELECT SUM(JobFiles) AS stored_files FROM Job ";
442 // Interval calculation
443 $end_date = mktime();
444 $start_date = $end_date - $delay;
446 $start_date = date( "Y-m-d H:i:s", $start_date );
447 $end_date = date( "Y-m-d H:i:s", $end_date );
450 $query .= "WHERE EndTime BETWEEN '$start_date' AND '$end_date'";
452 $result = $this->db_link->query( $query );
454 if( !PEAR::isError($result) ) {
455 $nbfiles = $result->fetchRow(DB_FETCHMODE_ASSOC);
456 $totalfiles = $totalfiles + $nbfiles['stored_files'];
458 die("Unable to get protected files from catalog <br />" . $result->getMessage() );
464 public function GetStoredBytes( $delay = LAST_DAY )
466 $query = "SELECT SUM(JobBytes) as stored_bytes FROM Job ";
468 // Interval calculation
469 $end_date = mktime();
470 $start_date = $end_date - $delay;
472 $start_date = date( "Y-m-d H:i:s", $start_date );
473 $end_date = date( "Y-m-d H:i:s", $end_date );
476 $query .= "WHERE EndTime BETWEEN '$start_date' AND '$end_date'";
478 $result = $this->db_link->query( $query );
480 if( PEAR::isError( $result ) ) {
481 die( "Unable to get Job Bytes from catalog" );
483 return $result->fetchRow( DB_FETCHMODE_ASSOC );
487 public function GetStoredBytesByInterval( $start_date, $end_date )
491 switch($this->driver) {
494 $query = "SELECT SUM(JobBytes) as stored_bytes FROM Job WHERE (EndTime BETWEEN '$start_date' AND '$end_date')";
497 $query = "SELECT SUM(JobBytes) as stored_bytes FROM Job WHERE (EndTime BETWEEN '$start_date' AND '$end_date')";
501 $result = $this->db_link->query( $query );
503 if( PEAR::isError( $result ) ) {
504 $this->TriggerDBError( "Unable to get Job Bytes from catalog", $result );
507 $tmp = $result->fetchRow( DB_FETCHMODE_ASSOC );
509 $day = date( "D d", strtotime($end_date) );
511 if( isset( $tmp['stored_bytes'] ) ) {
512 $hbytes = CUtils::Get_Human_Size( $tmp['stored_bytes'], 3, 'GB' );
513 $hbytes = explode( " ", $hbytes );
514 $stored_bytes = $hbytes[0];
517 return array( $day, $stored_bytes );
521 public function GetStoredBytesByJob( $jobname, $start_date, $end_date )
523 $query = "SELECT SUM(JobBytes) as stored_bytes, EndTime FROM Job ";
524 $query .= "WHERE ( EndTime BETWEEN '$start_date' AND '$end_date' ) AND ";
525 $query .= "Name = '$jobname'";
527 $result = $this->db_link->query( $query );
529 if( PEAR::isError( $result ) ) {
530 die( "Unable to get Job Bytes from catalog" );
533 $tmp = $result->fetchRow( DB_FETCHMODE_ASSOC );
535 $day = date( "D d", strtotime($end_date) );
537 if( isset( $tmp['stored_bytes'] ) ) {
538 $hbytes = CUtils::Get_Human_Size( $tmp['stored_bytes'], 3, 'GB' );
539 $hbytes = explode( " ", $hbytes );
540 $stored_bytes = $hbytes[0];
543 return array( $day, $stored_bytes );
547 public function GetStoredFilesByJob( $jobname, $start_date, $end_date )
549 $query = "SELECT SUM(JobFiles) as stored_files, EndTime FROM Job ";
550 $query .= "WHERE ( EndTime BETWEEN '$start_date' AND '$end_date' ) AND ";
551 $query .= "Name = '$jobname'";
553 $result = $this->db_link->query( $query );
555 if( PEAR::isError( $result ) ) {
556 die( "Unable to get Job Files from catalog" );
559 $tmp = $result->fetchRow( DB_FETCHMODE_ASSOC );
561 $day = date( "D d", strtotime($end_date) );
562 $stored_files = $tmp['stored_files'];
564 return array( $day, $stored_files );
568 private function TriggerDBError( $message, $db_error)
570 echo 'Error: ' . $message . '<br />';
571 echo 'Standard Message: ' . $db_error->getMessage() . '<br />';
572 echo 'Standard Code: ' . $db_error->getCode() . '<br />';
573 echo 'DBMS/User Message: ' . $db_error->getUserInfo() . '<br />';
574 echo 'DBMS/Debug Message: ' . $db_error->getDebugInfo() . '<br />';