if ($? == 0) {
my $content = $self->get_slot($src);
- print "content = $content<br/> $src => $dst<br/>";
+ print "$content ($src) => $dst<br/>";
$self->{slot}->[$src] = 'empty';
$self->set_slot($dst, $content);
return 1;
}
$all->{$vol}->{realslot} = $slot;
- $all->{$vol}->{volbytes} = Bweb::human_size($all->{$vol}->{volbytes}) ;
-
+
push @{ $param }, $all->{$vol};
} else { # empty or no label
unless ($self->{dbh});
$self->{dbh}->{FetchHashKeyName} = 'NAME_lc';
+
+ if ($self->{info}->{dbi} =~ /^dbi:Pg/i) {
+ $self->{dbh}->do("SET datestyle TO 'ISO, YMD'");
+ }
}
}
my $all = $self->dbh_selectall_hashref($query, 'name') ;
- foreach (values %$all) {
- $_->{fileretention} = human_sec($_->{fileretention});
- $_->{jobretention} = human_sec($_->{jobretention});
- }
-
my $dsp = { ID => $cur_id++,
clients => [ values %$all] };
priority => 10,
age => 60*60*24*7,
days => 1,
+ maxvoljobs => 0,
+ maxvolbytes => 0,
+ maxvolfiles => 0,
);
my %opt_s = ( # default to ''
ach => 1,
status => 1,
+ volstatus => 1,
+ inchanger => 1,
client => 1,
level => 1,
pool => 1,
graph => 1,
gtype => 1,
type => 1,
+ recyclepool => 1,
);
my %opt_p = ( # option with path
fileset=> 1,
device => 1,
);
+ my %opt_d = ( # option with date
+ voluseduration=> 1,
+ volretention => 1,
+ );
+
foreach my $i (@what) {
if (exists $opt_i{$i}) {# integer param
my $value = CGI::param($i) || $opt_i{$i} ;
if ($value =~ /^([\w\d\.\/\s:\@\-]+)$/) {
$ret{$i} = $1;
}
+ } elsif (exists $opt_d{$i}) {
+ my $value = CGI::param($i) || '';
+ if ($value =~ /^\s*(\d+\s+\w+)$/) {
+ $ret{$i} = $1;
+ }
}
}
my $all = $self->dbh_selectall_hashref($query, 'jobid') ;
- foreach (values %$all) {
- $_->{jobbytes} = human_size($_->{jobbytes}) ;
- }
-
$self->display({ clientname => $arg{clientname},
Filter => $label,
ID => $cur_id++,
my $status = CGI::param('status') || '';
if ($status =~ /^(\w)$/) {
$ret{status} = $1;
- $limit .= "AND Job.JobStatus = '$1' ";
+ if ($1 eq 'f') {
+ $limit .= "AND Job.JobStatus IN ('f','E') ";
+ } else {
+ $limit .= "AND Job.JobStatus = '$1' ";
+ }
}
}
get last backup
-SELECT DISTINCT Job.JobId AS jobid,
- Client.Name AS client,
- FileSet.FileSet AS fileset,
- Job.Name AS jobname,
- Level AS level,
- StartTime AS starttime,
- JobFiles AS jobfiles,
- JobBytes AS jobbytes,
- VolumeName AS volumename,
- JobStatus AS jobstatus,
- JobErrors AS joberrors
-
- FROM Client,Job,JobMedia,Media,FileSet
- WHERE Client.ClientId=Job.ClientId
- AND Job.FileSetId=FileSet.FileSetId
- AND JobMedia.JobId=Job.JobId
- AND JobMedia.MediaId=Media.MediaId
- $limit
-
=cut
sub display_job
my $all = $self->dbh_selectall_hashref($query, 'jobid') ;
- foreach (values %$all) {
- $_->{jobbytes} = human_size($_->{jobbytes}) ;
- }
-
$self->display({ Filter => $label,
ID => $cur_id++,
Jobs =>
JobFiles AS jobfiles,
JobBytes AS jobbytes,
JobStatus AS jobstatus,
+ JobErrors AS joberrors,
$self->{sql}->{SEC_TO_TIME}( $self->{sql}->{UNIX_TIMESTAMP}(EndTime)
- $self->{sql}->{UNIX_TIMESTAMP}(StartTime)) AS duration
my $row = $self->dbh_selectrow_hashref($query) ;
- $row->{jobbytes} = human_size($row->{jobbytes}) ;
-
# display all volumes associate with this job
$query="
SELECT Media.VolumeName as volumename
";
my $all = $self->dbh_selectall_hashref($query, 'volumename') ;
- foreach (values %$all) {
- $_->{volbytes} = human_size($_->{volbytes}) ;
- }
$self->display({ ID => $cur_id++,
Pool => $elt{pool},
my $all = $self->dbh_selectall_hashref($query, 'volumename') ;
foreach my $media (values %$all) {
- $media->{nb_bytes} = human_size($media->{nb_bytes}) ;
- $media->{voluseduration} = human_sec($media->{voluseduration});
- $media->{volretention} = human_sec($media->{volretention});
- $media->{volreadtime} = human_sec($media->{volreadtime});
- $media->{volwritetime} = human_sec($media->{volwritetime});
my $mq = $self->dbh_quote($media->{volumename});
$query = "
my $jobs = $self->dbh_selectall_hashref($query, 'jobid') ;
- foreach (values %$jobs) {
- $_->{bytes} = human_size($_->{bytes}) ;
- }
-
$query = "
SELECT LocationLog.Date AS date,
Location.Location AS location,
$self->display_location();
}
+sub location_del
+{
+ my ($self) = @_ ;
+ my $arg = $self->get_form(qw/qlocation/) ;
+
+ unless ($arg->{qlocation}) {
+ return $self->error("Can't get location");
+ }
+
+ my $query = "
+SELECT count(Media.MediaId) AS nb
+ FROM Media INNER JOIN Location USING (LocationID)
+WHERE Location = $arg->{qlocation}
+";
+
+ my $res = $self->dbh_selectrow_hashref($query);
+
+ if ($res->{nb}) {
+ return $self->error("Sorry, the location must be empty");
+ }
+
+ $query = "
+DELETE FROM Location WHERE Location = $arg->{qlocation} LIMIT 1
+";
+
+ $self->dbh_do($query);
+
+ $self->display_location();
+}
+
+
sub location_add
{
my ($self) = @_ ;
}
}
-sub do_update_media
-{
- my ($self) = @_ ;
-
- my $media = CGI::param('media');
- unless ($media) {
- return $self->error("Can't find media selection");
- }
-
- $media = $self->dbh_quote($media);
-
- my $update = '';
-
- my $volstatus = CGI::param('volstatus') || '';
- $volstatus = $self->dbh_quote($volstatus); # is checked by db
- $update .= " VolStatus=$volstatus, ";
-
- my $inchanger = CGI::param('inchanger') || '';
- if ($inchanger) {
- $update .= " InChanger=1, " ;
- my $slot = CGI::param('slot') || '';
- if ($slot =~ /^(\d+)$/) {
- $update .= " Slot=$1, ";
- } else {
- $update .= " Slot=0, ";
- }
- } else {
- $update = " Slot=0, InChanger=0, ";
- }
-
- my $pool = CGI::param('pool') || '';
- $pool = $self->dbh_quote($pool); # is checked by db
- $update .= " PoolId=(SELECT PoolId FROM Pool WHERE Name=$pool), ";
-
- my $volretention = CGI::param('volretention') || '';
- $volretention = from_human_sec($volretention);
- unless ($volretention) {
- return $self->error("Can't get volume retention");
- }
-
- $update .= " VolRetention = $volretention, ";
-
- my $loc = CGI::param('location') || '';
- $loc = $self->dbh_quote($loc); # is checked by db
- $update .= " LocationId=(SELECT LocationId FROM Location WHERE Location=$loc), ";
-
- my $usedu = CGI::param('voluseduration') || '0';
- $usedu = from_human_sec($usedu);
- $update .= " VolUseDuration=$usedu, ";
-
- my $maxj = CGI::param('maxvoljobs') || '0';
- unless ($maxj =~ /^(\d+)$/) {
- return $self->error("Can't get max jobs");
- }
- $update .= " MaxVolJobs=$1, " ;
-
- my $maxf = CGI::param('maxvolfiles') || '0';
- unless ($maxj =~ /^(\d+)$/) {
- return $self->error("Can't get max files");
- }
- $update .= " MaxVolFiles=$1, " ;
-
- my $maxb = CGI::param('maxvolbytes') || '0';
- unless ($maxb =~ /^(\d+)$/) {
- return $self->error("Can't get max bytes");
- }
- $update .= " MaxVolBytes=$1 " ;
-
- my $row=$self->dbh_do("UPDATE Media SET $update WHERE VolumeName=$media");
-
- if ($row) {
- print "Update Ok\n";
- $self->update_media();
- }
-}
-
sub update_media
{
my ($self) = @_ ;
Media.MaxVolJobs AS maxvoljobs,
Media.MaxVolFiles AS maxvolfiles,
Media.VolUseDuration AS voluseduration,
- Media.VolRetention AS volretention
+ Media.VolRetention AS volretention,
+ Media.Comment AS comment,
+ Media.RecyclePoolId AS recyclepoolid
FROM Media INNER JOIN Pool ON (Media.PoolId = Pool.PoolId)
LEFT JOIN Location ON (Media.LocationId = Location.LocationId)
$self->display({
%$elt,
%$row,
- },
- "update_media.tpl");
+ }, "update_media.tpl");
}
sub save_location
my $nb = $self->dbh_do($query);
- print "$nb media updated";
+ print "$nb media updated, you may have to update your autochanger.";
+
+ $self->display_media();
}
sub change_location
$row->{ID} = $cur_id++;
$row->{label} = $label;
- $row->{nb_bytes} = human_size($row->{nb_bytes}) ;
$self->display($row, "display_client_stats.tpl");
}
# TODO : afficher les tailles et les dates
my $query = "
-SELECT sum(subq.volmax) AS volmax,
- sum(subq.volnum) AS volnum,
- sum(subq.voltotal) AS voltotal,
+SELECT subq.volmax AS volmax,
+ subq.volnum AS volnum,
+ subq.voltotal AS voltotal,
Pool.Name AS name,
Pool.Recycle AS recycle,
Pool.VolRetention AS volretention,
WHERE Media.VolStatus = 'Full'
GROUP BY Media.MediaType
) AS media_avg_size ON (Media.MediaType = media_avg_size.MediaType)
- GROUP BY Media.MediaType, Media.PoolId
- ) AS subq
-INNER JOIN Pool ON (Pool.PoolId = subq.PoolId)
-GROUP BY subq.PoolId
+ GROUP BY Media.MediaType, Media.PoolId, media_avg_size.volavg
+ ) AS subq
+LEFT JOIN Pool ON (Pool.PoolId = subq.PoolId)
";
my $all = $self->dbh_selectall_hashref($query, 'name') ;
- foreach my $p (values %$all) {
- $p->{maxvolbytes} = human_size($p->{maxvolbytes}) ;
- $p->{volretention} = human_sec($p->{volretention}) ;
- $p->{voluseduration} = human_sec($p->{voluseduration}) ;
+ $query = "
+SELECT Pool.Name AS name,
+ sum(VolBytes) AS size
+FROM Media JOIN Pool ON (Media.PoolId = Pool.PoolId)
+WHERE Media.VolStatus IN ('Recycled', 'Purged')
+GROUP BY Pool.Name;
+";
+ my $empty = $self->dbh_selectall_hashref($query, 'name');
- if ($p->{volmax}) {
+ foreach my $p (values %$all) {
+ if ($p->{volmax} > 0) { # mysql returns 0.0000
+ # we remove Recycled/Purged media from pool usage
+ if (defined $empty->{$p->{name}}) {
+ $p->{voltotal} -= $empty->{$p->{name}}->{size};
+ }
$p->{poolusage} = sprintf('%.2f', $p->{voltotal} * 100/ $p->{volmax}) ;
} else {
$p->{poolusage} = 0;
sub eject_media
{
my ($self) = @_;
- my $arg = $self->get_form('jmedias', 'slots', 'ach');
+ my $arg = $self->get_form('jmedias');
unless ($arg->{jmedias}) {
return $self->error("Can't get media selection");
}
- my $a = $self->ach_get($arg->{ach});
- unless ($a) {
- return 0;
- }
-
my $query = "
SELECT Media.VolumeName AS volumename,
Storage.Name AS storage,
my $all = $self->dbh_selectall_hashref($query, 'volumename');
- $a->status();
-
foreach my $vol (values %$all) {
+ my $a = $self->ach_get($vol->{location});
+ next unless ($a) ;
+
+ unless ($a->{have_status}) {
+ $a->status();
+ $a->{have_status} = 1;
+ }
+
print "eject $vol->{volumename} from $vol->{storage} : ";
if ($a->send_to_io($vol->{slot})) {
print "ok</br>";
}
}
+sub move_email
+{
+ my ($self) = @_;
+
+ my ($to, $subject, $content) = (CGI::param('email'),
+ CGI::param('subject'),
+ CGI::param('content'));
+ $to =~ s/[^\w\d\.\@<>,]//;
+ $subject =~ s/[^\w\d\.\[\]]/ /;
+
+ open(MAIL, "|mail -s '$subject' '$to'") ;
+ print MAIL $content;
+ close(MAIL);
+
+ print "Mail sent";
+}
+
sub restore
{
my ($self) = @_;
my $ret = $b->send_cmd("delete jobid=\"$arg->{jobid}\"");
$self->display({
- content => $b->send_cmd("delete jobid=\"$arg->{jobid}\""),
+ content => $ret,
title => "Delete a job ",
name => "delete jobid=$arg->{jobid}",
}, "command.tpl");
}
}
+sub do_update_media
+{
+ my ($self) = @_ ;
+
+ my $arg = $self->get_form(qw/media volstatus inchanger pool
+ slot volretention voluseduration
+ maxvoljobs maxvolfiles maxvolbytes
+ qcomment recyclepool
+ /);
+
+ unless ($arg->{media}) {
+ return $self->error("Can't find media selection");
+ }
+
+ my $update = "update volume=$arg->{media} ";
+
+ if ($arg->{volstatus}) {
+ $update .= " volstatus=$arg->{volstatus} ";
+ }
+
+ if ($arg->{inchanger}) {
+ $update .= " inchanger=yes " ;
+ if ($arg->{slot}) {
+ $update .= " slot=$arg->{slot} ";
+ }
+ } else {
+ $update .= " slot=0 inchanger=no ";
+ }
+
+ if ($arg->{pool}) {
+ $update .= " pool=$arg->{pool} " ;
+ }
+
+ $arg->{volretention} ||= 0 ;
+ if ($arg->{volretention}) {
+ $update .= " volretention=\"$arg->{volretention}\" " ;
+ }
+
+ $arg->{voluseduration} ||= 0 ;
+ if ($arg->{voluseduration}) {
+ $update .= " voluse=\"$arg->{voluseduration}\" " ;
+ }
+
+ $arg->{maxvoljobs} ||= 0;
+ if ($arg->{maxvoljobs}) {
+ $update .= " maxvoljobs=$arg->{maxvoljobs} " ;
+ }
+
+ $arg->{maxvolfiles} ||= 0;
+ if ($arg->{maxvolfiles}) {
+ $update .= " maxvolfiles=$arg->{maxvolfiles} " ;
+ }
+
+ $arg->{maxvolbytes} ||= 0;
+ if ($arg->{maxvolbytes}) {
+ $update .= " maxvolbytes=$arg->{maxvolbytes} " ;
+ }
+
+ my $b = $self->get_bconsole();
+
+ $self->display({
+ content => $b->send_cmd($update),
+ title => "Update a volume ",
+ name => $update,
+ }, "command.tpl");
+
+
+ my @q;
+ my $media = $self->dbh_quote($arg->{media});
+
+ my $loc = CGI::param('location') || '';
+ if ($loc) {
+ $loc = $self->dbh_quote($loc); # is checked by db
+ push @q, "LocationId=(SELECT LocationId FROM Location WHERE Location=$loc)";
+ }
+ if ($arg->{recyclepool}) {
+ push @q, "RecyclePoolId=(SELECT PoolId FROM Pool WHERE Name='$arg->{recyclepool}')";
+ }
+ if (!$arg->{qcomment}) {
+ $arg->{qcomment} = "''";
+ }
+ push @q, "Comment=$arg->{qcomment}";
+
+
+ my $query = "
+UPDATE Media
+ SET " . join (',', @q) . "
+ WHERE Media.VolumeName = $media
+";
+ $self->dbh_do($query);
+
+ $self->update_media();
+}
+
sub update_slots
{
my ($self) = @_;
my $ach = CGI::param('ach') ;
- unless ($ach =~ /^([\w\d\.-]+)$/) {
+ $ach = $self->ach_get($ach);
+ unless ($ach) {
return $self->error("Bad autochanger name");
}
- my $b = $self->get_bconsole();
- print "<pre>" . $b->update_slots($ach) . "</pre>";
+ print "<pre>";
+ my $b = new Bconsole(pref => $self->{info},timeout => 60,log_stdout => 1);
+ $b->update_slots($ach->{name});
+ print "</pre>\n"
}
sub get_job_log
$query = "
SELECT Time AS time, LogText AS log
- FROM Log
- WHERE JobId = $arg->{jobid}
- ORDER BY Time
+ FROM Log INNER JOIN Job ON (Job.JobId = Log.JobId)
+ WHERE Log.JobId = $arg->{jobid}
+ OR ( Log.JobId = 0
+ AND Log.Time >= Job.StartTime
+ AND Log.Time <= COALESCE(Job.EndTime, Now())
+ )
+ ORDER BY LogId
";
+
my $log = $self->dbh_selectall_arrayref($query);
unless ($log) {
return $self->error("Can't get log for jobid $arg->{jobid}");
drive => $arg->{drive},
pool => 'Scratch',
slots => $slots) ;
- print "</pre>";
$b->close();
+ print "</pre>";
}
sub purge