From f8dc086e92ce12fd815e78c384b606b831b3c0d1 Mon Sep 17 00:00:00 2001 From: Eric Bollengier Date: Wed, 5 Dec 2007 18:05:03 +0000 Subject: [PATCH] ebl Add new btime module git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@6021 91ce42f0-d328-0410-95d8-f526ca767f89 --- gui/bweb/cgi/btime.pl | 265 +++++++++++++++++++++++++++ gui/bweb/lib/Bweb.pm | 2 + gui/bweb/lib/GTime.pm | 397 +++++++++++++++++++++++++++++++++++++++++ gui/bweb/technotes-2.3 | 4 + gui/bweb/tpl/btime.tpl | 176 ++++++++++++++++++ gui/debian/changelog | 5 + gui/debian/rules | 3 + 7 files changed, 852 insertions(+) create mode 100755 gui/bweb/cgi/btime.pl create mode 100644 gui/bweb/lib/GTime.pm create mode 100644 gui/bweb/tpl/btime.tpl diff --git a/gui/bweb/cgi/btime.pl b/gui/bweb/cgi/btime.pl new file mode 100755 index 0000000000..ca52f834c0 --- /dev/null +++ b/gui/bweb/cgi/btime.pl @@ -0,0 +1,265 @@ +#!/usr/bin/perl -w + +=head1 LICENSE + + Bweb - A Bacula web interface + Bacula® - The Network Backup Solution + + Copyright (C) 2000-2006 Free Software Foundation Europe e.V. + + The main author of Bweb is Eric Bollengier. + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation plus additions + that are listed in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of John Walker. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zurich, + Switzerland, email:ftf@fsfeurope.org. + +=cut + +use strict; +use GTime; +use Getopt::Long ; +use Bweb; +use Time::ParseDate qw/parsedate/; +use CGI; + +my $conf = new Bweb::Config(config_file => $Bweb::config_file); +$conf->load(); + +my $bweb = new Bweb(info => $conf); +my $arg = $bweb->get_form(qw/qiso_begin qiso_end qusage qpool qnojob + jclient_groups db_client_groups qclient_groups/); + +use Digest::MD5 qw(md5_hex); +my $md5_rep = md5_hex("$arg->{qiso_begin}:$arg->{qiso_end}:$arg->{qusage}:" . + "$arg->{jclient_groups}:$arg->{qpool};$arg->{qnojob}") ; + +print CGI::header('text/html'); +$bweb->display_begin(); + +if ($arg->{qiso_begin} && -f "$conf->{fv_write_path}/$md5_rep.png") { + $arg->{result} = "/bweb/fv/$md5_rep.png"; + $bweb->display($arg, 'btime.tpl'); + + $bweb->display_end(); + exit 0; +} + +my $top = new GTime( + debug => $conf->{debug}, + xmarge => 200, + type => { + spool => 1, + despool => 2, + commit => 4, + waiting => 3, + init => 5, + }) ; +my $sec = $bweb->{sql}->{STARTTIME_SEC}; +$sec =~ s/Job.StartTime/Log.Time/; +my $reg = $bweb->{sql}->{MATCH}; + + +my %regs1 = ( + end_job => ': Bacula [1-9]', + start_job => ': Start Backup', + data_despool_time => ': Despooling elapsed time', + attr_despool_time => ': Sending spooled attrs', + get_drive => ': Using Device', + start_spool => ': Spooling', + end_spool => ': User specified spool', + ); + + +my %regs = ( + end_job => ': Bacula [1-9]', + start_job => ': D.marrage du ', + data_despool_time => ': Temps du tran', + attr_despool_time => ': Transfert des', + get_drive => ': Using Device', + start_spool => ': Spooling', + end_spool => ': Taille du spool', + ); + +my $filter = join(" OR ", + map { "Log.LogText $bweb->{sql}->{MATCH} '$_'" } values %regs); + +my $query = " +SELECT " . $bweb->dbh_strcat('Job.Name', "'_'", 'Job.Level') . ", + $sec, + substring(Log.LogText from 1 for 65), + Job.JobId, + Pool.Name + +FROM Log INNER JOIN Job USING (JobId) JOIN Pool USING (PoolId) +" . ($arg->{jclient_groups}? +" JOIN Client USING (ClientId) + JOIN client_group_member ON (Client.ClientId = client_group_member.clientid) + JOIN client_group USING (client_group_id) + WHERE client_group_name IN ($arg->{jclient_groups}) + AND +":'WHERE') . +" + Job.StartTime > $arg->{qiso_begin} + AND Job.StartTime < $arg->{qiso_end} + AND ( $filter ) + AND Job.Type = 'B' +ORDER BY Job.JobId,Log.Time +"; + + +print STDERR $query if ($conf->{debug}) +my $all = $bweb->dbh_selectall_arrayref($query); + +my $lastid = 0; +my $lastspool = 0; +my $last_name; +my $data = []; +my $write = {}; +my $pool = {}; +my $drive = ""; +my $end; +my $begin; +foreach my $elt (@$all) +{ + if ($lastid && $lastid ne $elt->[3]) { + if (!$arg->{qnojob}) { + $top->add_job(label => $last_name, + data => $data); + } + $data = []; + $lastspool=0; + } + + if ($elt->[2] =~ /$regs{start_job}/) { + push @$data, { + type => "commit", + begin => $begin, + end => $elt->[1], + }; + + } elsif ($elt->[2] =~ /$regs{attr_despool_time}/) { + + push @$data, { + type => "waiting", + begin => $begin, + end => $elt->[1], + }; + + } elsif ($elt->[2] =~ /$regs{get_drive} "([\w\d]+)"/) { + $drive = $1; + + } elsif ($elt->[2] =~ /$regs{data_despool_time}.+? = (\d+):(\d+):(\d+)/) { + # on connait le temps de despool + my $t = $1*60*60+ $2*60 + $3; + + if ($t > 10) { # en dessous de 10s on affiche pas + push @$data, { # temps d'attente du drive + type => "waiting", + begin => $begin, + end => parsedate($elt->[1]) - $t, + }; + + push @$data, { + type => "despool", + begin => parsedate($elt->[1]) - $t, + end => $elt->[1], + }; + + push @{$write->{$drive}}, { # display only write time + type => "despool", + begin => parsedate($elt->[1]) - $t, + end => $elt->[1], + }; + + push @{$pool->{"$drive: $elt->[4]"}}, { + type => "despool", + begin => parsedate($elt->[1]) - $t, + end => $elt->[1], + }; + } else { + push @$data, { + type => "waiting", + begin => $begin, + end => $elt->[1], + }; + } + + } elsif ($elt->[2] =~ /$regs{start_spool}/) { + + if (!$lastspool) { + push @$data, { + type => "init", + begin => $begin, + end => $elt->[1], + }; + } + + $lastspool = 1; + + } elsif ($elt->[2] =~ /($regs{end_spool}|$regs{attr_despool_time})/) { + push @$data, { + type => "spool", + begin => $begin, + end => $elt->[1], + }; + + } elsif ($elt->[2] =~ /$regs{end_job}/) { + 1; + } else { + next; + } + + $end = $begin; + $begin = $elt->[1]; + $last_name = $elt->[0]; + $lastid = $elt->[3]; +} + +if (!$arg->{qnojob} && $last_name) { + $top->add_job(label => $last_name, + data => $data); +} +if ($arg->{qpool}) { + foreach my $d (sort keys %$pool) { + $top->add_job(label => $d, + data => $pool->{$d}); + } +} + +if ($arg->{qusage}) { + foreach my $d (sort keys %$write) { + $top->add_job(label => "drive $d", + data => $write->{$d}); + } +} + + +$top->finalize(); + +open(FP, ">$conf->{fv_write_path}/$md5_rep.png"); +binmode FP; +# Convert the image to PNG and print it on standard output +print FP $GTime::gd->png; +close(FP); + +$arg->{result} = "/bweb/fv/$md5_rep.png"; +$bweb->display( $arg, 'btime.tpl'); +$bweb->display_end(); diff --git a/gui/bweb/lib/Bweb.pm b/gui/bweb/lib/Bweb.pm index 94fa818ce4..983fd23326 100644 --- a/gui/bweb/lib/Bweb.pm +++ b/gui/bweb/lib/Bweb.pm @@ -1050,6 +1050,7 @@ our %sql_func = ( SEC_TO_INT => "SEC_TO_INT", SEC_TO_TIME => '', MATCH => " ~* ", + STARTTIME_SEC => " date_trunc('sec', Job.StartTime) ", STARTTIME_DAY => " date_trunc('day', Job.StartTime) ", STARTTIME_HOUR => " date_trunc('hour', Job.StartTime) ", STARTTIME_MONTH => " date_trunc('month', Job.StartTime) ", @@ -1069,6 +1070,7 @@ our %sql_func = ( TO_SEC => '', SEC_TO_TIME => 'SEC_TO_TIME', MATCH => " REGEXP ", + STARTTIME_SEC => " DATE_FORMAT(Job.StartTime, '%Y-%m-%d %T') ", STARTTIME_DAY => " DATE_FORMAT(Job.StartTime, '%Y-%m-%d') ", STARTTIME_HOUR => " DATE_FORMAT(Job.StartTime, '%Y-%m-%d %H') ", STARTTIME_MONTH => " DATE_FORMAT(Job.StartTime, '%Y-%m') ", diff --git a/gui/bweb/lib/GTime.pm b/gui/bweb/lib/GTime.pm new file mode 100644 index 0000000000..bed4ac39e1 --- /dev/null +++ b/gui/bweb/lib/GTime.pm @@ -0,0 +1,397 @@ +#!/usr/bin/perl -w + +=head1 LICENSE + + Bweb - A Bacula web interface + Bacula® - The Network Backup Solution + + Copyright (C) 2000-2006 Free Software Foundation Europe e.V. + + The main author of Bweb is Eric Bollengier. + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation plus additions + that are listed in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of John Walker. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zurich, + Switzerland, email:ftf@fsfeurope.org. + +=cut + +use strict ; +use GD qw/gdSmallFont/; + +package GTime ; + +my $pi = 3.14159265; + +our $gd ; +our @color_tab ; + +our $black ; +our $white ; + +our $last_level = 1 ; +our @draw_label ; +our $height ; +our $width ; + +our $cur_color = 1 ; + +my $debug = 1 ; +my $font_size = 6 ; + +our @image_map ; + +sub new +{ + my ($class, %arg) = @_ ; + + my $self = { + height => 800, # element height in px + width => 600, # element width in px + xmarge => 150, + + cbegin => 0, # compute begin + cend => 0, # compute end + + begin => 0, # user start + end => 0, # user end + + cur_y => 0, # current y position + elt_h => 20, # elt height in px + + data => [], + type => {}, + + base_url => '', + } ; + + map { $self->{$_} = $arg{$_} } keys %arg ; + + if ($self->{begin}) { + $self->{begin} = parsedate($self->{begin}); + } + if ($self->{end}) { + $self->{end} = parsedate($self->{end}); + } + + bless $self ; + + return $self ; +} + +my $_image_map = ''; + +sub get_imagemap +{ + my ($self, $title, $img) = @_ ; + + return " + + $_image_map + + +" ; + +} + +sub push_image_map +{ + my ($self, $label, $tips, $x1, $y1, $x2, $y2) = @_ ; + + my $ret = sprintf("%.2f,%.2f,%.2f,%.2f,%.2f,%.2f", + $x1,$y1,$x1,$y2,$x2,$y2); + + $_image_map .= "\n" ; +} + +use Data::Dumper; +sub debug +{ + my ($self, $what) = @_; + + if ($self->{debug}) { + if (ref $what) { + print STDERR Data::Dumper::Dumper($what); + } else { + print STDERR "$what\n"; + } + } +} + +use Time::ParseDate qw/parsedate/; + +sub add_job +{ + my ($self, %elt) = @_; + + foreach my $d (@{$elt{data}}) { + + if ($d->{begin} !~ /^\d+$/) { # date => second + $d->{begin} = parsedate($d->{begin}); + } + + if ($d->{end} !~ /^\d+$/) { # date => second + $d->{end} = parsedate($d->{end}); + } + + if ($self->{cbegin} == 0) { + $self->{cbegin} = $d->{begin}; + $self->{cend} = $d->{end}; + } + + # calculate begin and end graph + if ($self->{cbegin} > $d->{begin}) { + $self->{cbegin}= $d->{begin}; + } + if ($self->{cend} < $d->{end}) { + $self->{cend} = $d->{end}; + } + + # TODO: check elt + } + + push @{$self->{data}}, \%elt; +} + +# si le label est identique, on reste sur la meme ligne +# sinon, on prend la ligne suivante +sub get_y +{ + my ($self, $label) = @_; + + unless ($self->{label_y}->{$label}) { + $self->{label_y}->{$label} = $self->{cur_y}; + $self->{cur_y} += $self->{elt_h} + 5; + } + + return $self->{label_y}->{$label} ; +} + +sub get_color +{ + my ($self, $label) = @_; + + return 1 unless ($label); + + unless ($self->{type}->{$label}) { + $self->{type}->{$label} = 1; + } + + return $self->{type}->{$label} ; +} + +sub draw_elt +{ + my ($self, $elt, $y1) = @_; + use integer; + + my $y2 = $self->{height} - ($y1 + $self->{elt_h}) ; + $y1 = $self->{height} - $y1; + + my $x1 = $self->{xmarge} + ($elt->{begin} - $self->{cbegin}) * $self->{width}/ $self->{period} ; + my $x2 = $self->{xmarge} + ($elt->{end} - $self->{cbegin}) * $self->{width}/ $self->{period} ; + + my $color = $self->get_color($elt->{type}); + + $gd->rectangle($x1,$y1, + $x2,$y2, + $black); + if (($x1 + 4) <= $x2) { + $gd->fill(($x1 + $x2)/2, + ($y1 + $y2)/2, + $color_tab[$color]); + } +} + +sub init_gd +{ + my ($self) = @_; + + unless (defined $gd) { + my $height = $self->{height} ; + my $width = $self->{width} ; + + $gd = new GD::Image($width+350,$height+200); + $white = $gd->colorAllocate(255,255,255); + + push @color_tab, ($gd->colorAllocate(135,236,88), + $gd->colorAllocate( 255, 236, 139), + $gd->colorAllocate(255,95,95), + $gd->colorAllocate(255,149,0), + $gd->colorAllocate( 255, 174, 185), + $gd->colorAllocate( 179, 255, 58), + $gd->colorAllocate( 205, 133, 0), + $gd->colorAllocate(205, 133, 0 ), + $gd->colorAllocate(238, 238, 209), + ) ; + + $black = $gd->colorAllocate(0,0,0); + #$gd->transparent($white); + $gd->interlaced('true'); + # x y x y + $gd->line($self->{xmarge},10, $self->{xmarge}, $height, $color_tab[1]); + $gd->line($self->{xmarge},$height, $width, $height, $black); + } +} +use POSIX qw/strftime/; + +sub finalize +{ + my ($self) = @_; + + my $nb_elt = scalar(@{$self->{data}}); + # (4 drive + nb job) * (size of elt) + $self->{height} = (4+$nb_elt) * ($self->{elt_h} + 5); + + $self->init_gd(); + + if ($self->{begin}) { + $self->{cbegin} = $self->{begin}; + } + if ($self->{end}) { + $self->{cend} = $self->{end}; + } + + $self->{period} = $self->{cend} - $self->{cbegin}; + return if ($self->{period < 1); + + foreach my $elt (@{$self->{data}}) { + my $y1 = $self->get_y($elt->{label}); + + $gd->string(GD::Font->Small, + 1, # x + $self->{height} - $y1 - 12, + $elt->{label}, $black); + + foreach my $d (@{$elt->{data}}) { + $self->draw_elt($d, $y1); + } + } + + for my $i (0..10) { + my $x1 = $i/10*$self->{width} + $self->{xmarge} ; + $gd->stringUp(GD::Font->Small, + $x1, # x + $self->{height} + 100, # y + strftime('%D %H:%M', localtime($i/10*$self->{period}+$self->{cbegin})), $black); + + $gd->dashedLine($x1, + $self->{height} + 100, + $x1, + 100, + $black); + } + + # affichage des legendes + my $x1=100; + my $y1=$self->{height} + 150; + + for my $t (keys %{$self->{type}}) { + my $color = $self->get_color($t); + + $gd->rectangle($x1 - 5, + $y1 - 10, + $x1 + length($t)*10 - 5, + $y1 + 15, + $color_tab[$color]); + + $gd->fill($x1, $y1, $color_tab[$color]); + + $gd->string(GD::Font->Small, + $x1, + $y1, + $t, + $black); + $x1 += length($t)*10; + } + + #binmode STDOUT; + #print $gd->png; +} + + +1; +__END__ + +package main ; + +my $begin1 = "2006-10-03 09:59:34"; +my $end1 = "2006-10-03 10:59:34"; + +my $begin2 = "2006-10-03 11:59:34"; +my $end2 = "2006-10-03 13:59:34"; + +my $top = new GTime(debug => 1, + type => { + init => 2, + write => 3, + commit => 4, + }) ; + +$top->add_job(label => "label", + data => [ + { + type => "init", + begin => $begin1, + end => $end1, + }, + + { + type => "write", + begin => $end1, + end => $begin2, + }, + + { + type => "commit", + begin => $begin2, + end => $end2, + }, + ]); + +$top->add_job(label => "label2", + data => [ + { + type => "init", + begin => $begin1, + end => $end1, + }, + + { + type => "write", + begin => $end1, + end => $begin2, + }, + + { + type => "commit", + begin => $begin2, + end => $end2, + }, + ]); + +$top->finalize() ; +#$top->draw_labels() ; +# make sure we are writing to a binary stream +binmode STDOUT; + +# Convert the image to PNG and print it on standard output +print $gd->png; diff --git a/gui/bweb/technotes-2.3 b/gui/bweb/technotes-2.3 index 8d98767525..839797c996 100644 --- a/gui/bweb/technotes-2.3 +++ b/gui/bweb/technotes-2.3 @@ -1,3 +1,7 @@ +05Dec07 +ebl Add truncate to second function +ebl Add btime module + 28Nov07 ebl Fix the time slice between overview and overview_zoom diff --git a/gui/bweb/tpl/btime.tpl b/gui/bweb/tpl/btime.tpl new file mode 100644 index 0000000000..53d254b234 --- /dev/null +++ b/gui/bweb/tpl/btime.tpl @@ -0,0 +1,176 @@ +
+

Timing Statistics

+
+
+ + + +
+
+
+ Options   +
+
+ + + + + + + + + + + + + + + +
+

Time limits

+ + + +
Begin: value= + size='16'> +
End: value= + size='16'> +
+
+

Graph

+ checked="checked" value='on' + name="usage"> Drive usage
+ checked="checked" value='on' + name="pool"> Pool usage
+ checked="checked" value='on' + name="nojob"> Hide Job
+ +
+

Groups

+ +
+ +
+
+ +
+
+ +
+ Current   +
+
+ Nothing to display, Try a bigger date range +
+ +
+
+ + + diff --git a/gui/debian/changelog b/gui/debian/changelog index 238e7c25e1..7572df84f0 100644 --- a/gui/debian/changelog +++ b/gui/debian/changelog @@ -1,3 +1,8 @@ +bweb (2.2.7-1) stable; urgency=low + * Add new btime module + + -- Eric Bollengier Tue, 4 Dec 2007 22:15:47 +0000 + bweb (2.2.6-1) stable; urgency=low * Replace VolStatus by Enabled in volume location * Add Enabled in volume update and zoom diff --git a/gui/debian/rules b/gui/debian/rules index 989f089df9..26970908cb 100755 --- a/gui/debian/rules +++ b/gui/debian/rules @@ -51,9 +51,12 @@ install-indep: install -m 644 bweb/lib/Bconsole.pm debian/bweb-common/usr/share/perl5 install -m 644 bweb/lib/CCircle.pm debian/bweb/usr/share/perl5 install -m 644 bweb/lib/Bweb.pm debian/bweb/usr/share/perl5 + install -m 644 bweb/lib/GTime.pm debian/bweb/usr/share/perl5 install -m 644 bweb/script/bweb.conf debian/bweb/etc/apache/conf.d install -m 755 bweb/cgi/bgraph.pl debian/bweb/usr/lib/cgi-bin/bweb install -m 755 bweb/cgi/bweb.pl debian/bweb/usr/lib/cgi-bin/bweb + install -m 755 bweb/cgi/btime.pl debian/bweb/usr/lib/cgi-bin/bweb + install -m 755 bweb/cgi/bresto.pl debian/bweb/usr/lib/cgi-bin/bweb install -m 755 bweb/cgi/bfileview.pl debian/bweb/usr/lib/cgi-bin/bweb install -m 755 bweb/cgi/bconsole.pl debian/bweb/usr/lib/cgi-bin/bweb install -m 644 bweb/tpl/*.tpl debian/bweb/usr/share/bweb/tpl -- 2.39.5