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 $this->db_link = $this->connect( $dsn );
49 if (DB::isError($this->db_link)) {
50 die( 'Unable to connect to catalog <br />' . $this->db_link->getMessage());
52 $this->driver = $dsn['phptype'];
53 register_shutdown_function(array(&$this,'close') );
56 // Initialize smarty template classe
58 // Initialize smarty gettext function
59 $this->init_gettext();
62 if( $this->catalog_nb > 1 ) {
63 // Set current catalog in header template
64 if(isset( $_POST['catalog_id'] ) )
65 $this->tpl->assign( 'catalog_current', $_POST['catalog_id'] );
67 $this->tpl->assign( 'catalogs', $this->bwcfg->Get_Catalogs() );
71 // Initialize Smarty template classe
74 $this->tpl = new Smarty();
76 $this->tpl->compile_check = true;
77 $this->tpl->debugging = false;
78 $this->tpl->force_compile = true;
80 $this->tpl->template_dir = "./templates";
81 $this->tpl->compile_dir = "./templates_c";
82 $this->tpl->config_dir = "./configs";
85 function init_gettext()
87 global $smarty_gettext_path;
89 if ( function_exists("gettext") ) {
90 require_once( BW_SMARTY_GETTEXT . "smarty_gettext.php" );
91 $this->tpl->register_block('t','smarty_translate');
93 $language = $this->bwcfg->Get_Config_Param("lang");
95 putenv("LANG=$language");
96 setlocale(LC_ALL, $language);
97 bindtextdomain($domain,"./locale");
101 function smarty_translate($params, $text, &$smarty) {
104 $smarty->register_block('t','smarty_translate');
110 $this->db_link->disconnect();
118 switch( $this->driver )
121 $query = "SELECT table_schema AS 'database', sum( data_length + index_length) AS 'dbsize' ";
122 $query .= "FROM information_schema.TABLES ";
123 $query .= "WHERE table_schema = 'bacula' ";
124 $query .= "GROUP BY table_schema";
127 $query = "SELECT pg_database_size('bacula') AS dbsize";
130 // Not yet implemented
135 $result = $this->db_link->query( $query );
137 if(! PEAR::isError( $result ) )
139 $db = $result->fetchRow( DB_FETCHMODE_ASSOC );
140 $database_size = $db['dbsize'];
142 die( "Unable to get database size<br />" . $result->getMessage() );
144 return CUtils::Get_Human_Size( $database_size );
145 } // end function GetDbSize()
147 public function Get_Nb_Clients()
149 $clients = $this->db_link->query("SELECT COUNT(*) AS nb_client FROM Client");
150 if( PEAR::isError($clients) )
151 die( "Unable to get client number" );
153 return $clients->fetchRow( DB_FETCHMODE_ASSOC );
156 // Return an array of volumes ordered by poolid and volume name
157 function GetVolumeList() {
163 // Get the list of pools id
164 $query = "SELECT Pool.poolid, Pool.name FROM Pool ORDER BY Pool.poolid";
166 //$this->db_link->setFetchMode(DB_FETCHMODE_ASSOC);
167 $pools = $this->db_link->query( $query );
169 if( PEAR::isError( $pools ) )
170 die("Error: Failed to get pool list <br />SQL Query: $query<br />" . $pools->getMessage() );
172 while( $pool = $pools->fetchRow( DB_FETCHMODE_ASSOC ) ) {
173 switch( $this->driver )
176 $query = "SELECT Media.volumename, Media.volbytes, Media.volstatus, Media.mediatype, Media.lastwritten, Media.volretention
177 FROM Media LEFT JOIN Pool ON Media.poolid = Pool.poolid
178 WHERE Media.poolid = '". $pool['poolid'] . "' ORDER BY Media.volumename";
181 $query = "SELECT media.volumename, media.volbytes, media.volstatus, media.mediatype, media.lastwritten, media.volretention
182 FROM media LEFT JOIN pool ON media.poolid = pool.poolid
183 WHERE media.poolid = '". $pool['poolid'] . "' ORDER BY media.volumename";
186 $query = ""; // not yet implemented
192 $medias = $this->db_link->query( $query );
194 if( PEAR::isError( $medias ) ) {
195 die( "Failed to get media list for pool $volume[0] <br /> " . $medias->getMessage() );
197 if( $debug ) echo "Found " . $medias->numRows() . " medias for pool " . $pool['name'] . " <br />";
199 // Create array key for each pool
200 if( !array_key_exists( $pool['name'], $volumes) )
202 $volumes[ $pool['name'] ] = array();
204 while( $media = $medias->fetchRow( DB_FETCHMODE_ASSOC ) ) {
208 // If the pool is empty (no volumes in this pool)
209 if( $medias->numRows() == 0 ) {
210 if( $debug ) echo "No media in pool " . $pool['name'] . "<br />";
212 if( $media['lastwritten'] != "0000-00-00 00:00:00" ) {
213 // Calculate expiration date if the volume is Full
214 if( $media['volstatus'] == 'Full' ) {
215 $expire_date = strtotime($media['lastwritten']) + $media['volretention'];
216 $media['expire'] = strftime("%Y-%m-%d", $expire_date);
218 $media['expire'] = 'N/A';
220 // Media used bytes in a human format
221 $media['volbytes'] = CUtils::Get_Human_Size( $media['volbytes'] );
223 $media['lastwritten'] = "N/A";
224 $media['expire'] = "N/A";
225 $media['volbytes'] = "0 KB";
229 if( count( $volumes[ $pool['name'] ] ) % 2)
230 $media['class'] = 'odd';
232 // Add the media in pool array
233 array_push( $volumes[ $pool['name']], $media);
239 } // end function GetVolumeList()
241 public function CountJobsbyLevel( $delay = LAST_DAY, $level = 'F' )
243 $end_date = mktime();
244 $start_date = $end_date - $delay;
246 $start_date = date( "Y-m-d H:i:s", $start_date );
247 $end_date = date( "Y-m-d H:i:s", $end_date );
249 $query = "SELECT COUNT(JobId) as jobs FROM Job ";
250 $query .= "WHERE (EndTime BETWEEN '$start_date' AND '$end_date') AND ";
251 $query .= "Level = '$level' ";
253 $result = $this->db_link->query( $query );
255 if (PEAR::isError( $result ) ) {
256 die( "Unable to get number of jobs with $level status from catalog <br />" . $result->getMessage() );
258 $jobs = $result->fetchRow( DB_FETCHMODE_ASSOC );
259 return $jobs['jobs'];
264 public function CountJobs( $delay = LAST_DAY, $status = 'any' )
266 $query = "SELECT COUNT(JobId) AS job_nb FROM Job ";
270 // Interval condition for SQL query
271 if( $delay != ALL ) {
272 $end_date = mktime();
273 $start_date = $end_date - $delay;
275 $start_date = date( "Y-m-d H:i:s", $start_date );
276 $end_date = date( "Y-m-d H:i:s", $end_date );
278 $where_delay = "WHERE EndTime BETWEEN '$start_date' AND '$end_date' ";
281 if( $status != 'any' ) {
285 $where_status = "JobStatus = 'T' ";
288 $where_status = "JobStatus IN ('f','E') ";
291 $where_status = "JobStatus = 'A' ";
294 $where_status = "JobStatus IN ('F','S','M','m','s','j','c','d','t') ";
299 if( !empty($where_delay) )
300 $query = $query . $where_delay . 'AND ' . $where_status;
302 if( !empty($where_status) )
303 $query = $query . 'WHERE ' . $where_status;
306 $jobs = $this->db_link->query( $query );
308 if (PEAR::isError( $jobs ) ) {
309 die( "Unable to get last $status jobs number from catalog <br />" . $jobs->getMessage() );
311 $jobs = $jobs->fetchRow( DB_FETCHMODE_ASSOC );
312 return $jobs['job_nb'];
316 // Return the list of Pools in a array
317 public function Get_Pools_List()
319 $pool_list = array();
322 $query = "SELECT Name, PoolId FROM Pool";
324 $result = $this->db_link->query ( $query );
326 if( PEAR::isError( $result ) ) {
327 die( "Unable to get the pool list from catalog" );
329 while( $pool = $result->fetchRow(DB_FETCHMODE_ASSOC) ) {
330 array_push( $pool_list, array( $pool['Name'] => $pool['PoolId'] ) );
336 public function Get_BackupJob_Names()
338 $query = "SELECT Name FROM Job GROUP BY Name";
339 $backupjobs = array();
341 $result = $this->db_link->query( $query );
343 if (PEAR::isError( $result ) ) {
344 die("Unable to get BackupJobs list from catalog" );
346 while( $backupjob = $result->fetchRow( DB_FETCHMODE_ASSOC ) ) {
347 array_push( $backupjobs, $backupjob["Name"] );
353 // Return Jobs statistics for a specific interval such as
354 // - Completed jobs number
355 // - Failed jobs number
356 // - Waiting jobs number
357 // The returned values will be used by a Bgraph classe
358 public function GetJobsStatistics( $type = 'completed', $delay = LAST_DAY )
366 // Interval calculation
367 $end_date = mktime();
368 $start_date = $end_date - $delay;
370 $start_date = date( "Y-m-d H:i:s", $start_date );
371 $end_date = date( "Y-m-d H:i:s", $end_date );
373 $interval_where = "(EndTime BETWEEN '$start_date' AND '$end_date') AND ";
379 $where = $interval_where . "JobStatus = 'T' ";
380 $label = "Completed";
382 case 'terminated_errors':
383 $where = $interval_where . "JobStatus = 'E' ";
384 $label = "Terminated with errors";
387 $where = $interval_where . "JobStatus = 'f' ";
391 $where = "JobStatus IN ('F','S','M','m','s','j','c','d','t') ";
395 $where = "JobStatus = 'C' ";
396 $label = "Created but not running";
399 $where = "JobStatus = 'R' ";
403 $where = $interval_where . "JobStatus IN ('e','f') ";
408 $query = 'SELECT COUNT(JobId) AS ' . $type . ' ';
409 $query .= 'FROM Job ';
410 $query .= "WHERE $where ";
412 //echo 'query = ' . $query . '<br />';
414 $jobs = $this->db_link->query( $query );
416 if (PEAR::isError( $jobs ) ) {
417 die( "Unable to get last $type jobs status from catalog<br />" . $status->getMessage() );
419 $res = $jobs->fetchRow();
420 return array( $label , current($res) );
422 } // end function GetJobsStatistics()
424 public function CountVolumesByPool( $pools )
426 foreach( $pools as $pool_name => $pool ) {
428 $query = "SELECT COUNT(*) AS nb_vol FROM Media WHERE PoolId = '$pool'";
429 //echo $query . '<br />';
430 //echo 'Pool name ' . $pool_name . '<br />';
431 $result = $this->db_link->query( $query );
433 if( PEAR::isError( $result ) ) {
434 die("Unable to get volume number from catalog");
436 $nb_vol = $result->fetchRow(DB_FETCHMODE_ASSOC);
437 return array( $pool_name, $nb_vol['nb_vol'] );
442 public function GetStoredFiles( $delay = LAST_DAY )
446 $query = "SELECT SUM(JobFiles) AS stored_files FROM Job ";
448 // Interval calculation
449 $end_date = mktime();
450 $start_date = $end_date - $delay;
452 $start_date = date( "Y-m-d H:i:s", $start_date );
453 $end_date = date( "Y-m-d H:i:s", $end_date );
456 $query .= "WHERE EndTime BETWEEN '$start_date' AND '$end_date'";
458 $result = $this->db_link->query( $query );
460 if( !PEAR::isError($result) ) {
461 $nbfiles = $result->fetchRow(DB_FETCHMODE_ASSOC);
462 $totalfiles = $totalfiles + $nbfiles['stored_files'];
464 die("Unable to get protected files from catalog <br />" . $result->getMessage() );
470 public function GetStoredBytes( $delay = LAST_DAY )
472 $query = "SELECT SUM(JobBytes) as stored_bytes FROM Job ";
474 // Interval calculation
475 $end_date = mktime();
476 $start_date = $end_date - $delay;
478 $start_date = date( "Y-m-d H:i:s", $start_date );
479 $end_date = date( "Y-m-d H:i:s", $end_date );
482 $query .= "WHERE EndTime BETWEEN '$start_date' AND '$end_date'";
484 $result = $this->db_link->query( $query );
486 if( PEAR::isError( $result ) ) {
487 die( "Unable to get Job Bytes from catalog" );
489 return $result->fetchRow( DB_FETCHMODE_ASSOC );
493 public function GetStoredBytesByInterval( $start_date, $end_date )
495 $query = "SELECT SUM(JobBytes) as stored_bytes, EndTime FROM Job WHERE EndTime BETWEEN '$start_date' AND '$end_date'";
497 $result = $this->db_link->query( $query );
499 if( PEAR::isError( $result ) ) {
500 die( "Unable to get Job Bytes from catalog" );
503 $tmp = $result->fetchRow( DB_FETCHMODE_ASSOC );
505 $day = date( "D d", strtotime($end_date) );
507 if( isset( $tmp['stored_bytes'] ) ) {
508 $hbytes = CUtils::Get_Human_Size( $tmp['stored_bytes'], 3, 'GB' );
509 $hbytes = explode( " ", $hbytes );
510 $stored_bytes = $hbytes[0];
513 return array( $day, $stored_bytes );
517 public function GetStoredBytesByJob( $jobname, $start_date, $end_date )
519 $query = "SELECT SUM(JobBytes) as stored_bytes, EndTime FROM Job ";
520 $query .= "WHERE ( EndTime BETWEEN '$start_date' AND '$end_date' ) AND ";
521 $query .= "Name = '$jobname'";
523 $result = $this->db_link->query( $query );
525 if( PEAR::isError( $result ) ) {
526 die( "Unable to get Job Bytes from catalog" );
529 $tmp = $result->fetchRow( DB_FETCHMODE_ASSOC );
531 $day = date( "D d", strtotime($end_date) );
533 if( isset( $tmp['stored_bytes'] ) ) {
534 $hbytes = CUtils::Get_Human_Size( $tmp['stored_bytes'], 3, 'GB' );
535 $hbytes = explode( " ", $hbytes );
536 $stored_bytes = $hbytes[0];
539 return array( $day, $stored_bytes );
543 public function GetStoredFilesByJob( $jobname, $start_date, $end_date )
545 $query = "SELECT SUM(JobFiles) as stored_files, EndTime FROM Job ";
546 $query .= "WHERE ( EndTime BETWEEN '$start_date' AND '$end_date' ) AND ";
547 $query .= "Name = '$jobname'";
549 $result = $this->db_link->query( $query );
551 if( PEAR::isError( $result ) ) {
552 die( "Unable to get Job Files from catalog" );
555 $tmp = $result->fetchRow( DB_FETCHMODE_ASSOC );
557 $day = date( "D d", strtotime($end_date) );
558 $stored_files = $tmp['stored_files'];
560 return array( $day, $stored_files );