'delete_graphs' => { label => 'Delete associated graphs and data sources when unprovisioning',
type => 'checkbox',
},
+ 'include_path' => { label => 'Path to cacti include dir (relative to script_path)',
+ default => '../site/include/' },
'cacti_graph_template_id' => {
'label' => 'Graph Template',
'type' => 'custom',
'hostname' => $svc_broadband->ip_addr,
'script_path' => $self->option('script_path'),
'delete_graphs' => $self->option('delete_graphs'),
+ 'include_path' => $self->option('include_path'),
);
return ($queue,$error);
}
# $desc =~ s/'/'\\''/g;
$desc =~ s/'//g;
my $cmd = $php
- . $opt{'script_path'}
+ . trailslash($opt{'script_path'})
. q(add_device.php --description=')
. $desc
. q(' --ip=')
# Add host to tree
if ($opt{'tree_id'}) {
$cmd = $php
- . $opt{'script_path'}
+ . trailslash($opt{'script_path'})
. q(add_tree.php --type=node --node-type=host --tree-id=)
. $opt{'tree_id'}
. q( --host-id=)
# Get list of graph templates for new id
$cmd = $php
- . $opt{'script_path'}
+ . trailslash($opt{'script_path'})
. q(freeside_cacti.php --get-graph-templates --host-template=)
. $opt{'template_id'};
+ $cmd .= q( --include-path=') . $self->option('include_path') . q(')
+ if $self->option('include_path');
my $ginfo = { map { $_ ? ($_ => undef) : () } split(/\n/,ssh_cmd(%opt, 'command' => $cmd)) };
# Add extra config info
# create the graph
$cmd = $php
- . $opt{'script_path'}
+ . trailslash($opt{'script_path'})
. q(add_graphs.php --graph-type=)
. ($isds ? 'ds' : 'cg')
. q( --graph-template-id=)
sub ssh_delete {
my %opt = @_;
my $cmd = $php
- . $opt{'script_path'}
+ . trailslash($opt{'script_path'})
. q(freeside_cacti.php --drop-device --ip=')
. $opt{'hostname'}
. q(');
$cmd .= q( --delete-graphs)
if $opt{'delete_graphs'};
+ $cmd .= q( --include-path=') . $opt{'include_path'} . q(')
+ if $opt{'include_path'};
my $response = ssh_cmd(%opt, 'command' => $cmd);
die "Error removing from cacti: " . $response
if $response;
my ($job,$param) = @_;
$job->update_statustext(10);
- my $cachedir = $FS::UID::cache_dir . '/cacti-graphs/';
+ my $cachedir = trailslash($FS::UID::cache_dir,'cache.'.$FS::UID::datasrc,'cacti-graphs');
# load the service
my $svcnum = $param->{'svcnum'} || die "No svcnum specified";
# check for existing pages
my $now = time;
- my @oldpages = qsearch({
+ my %oldpages = map { ($_->graphnum || 'MAIN') => $_ } qsearch({
'table' => 'cacti_page',
'hashref' => { 'svcnum' => $svcnum, 'exportnum' => $self->exportnum },
- 'select' => 'cacti_pagenum, exportnum, svcnum, graphnum, imported', #no need to load old content
+ 'select' => 'cacti_pagenum, exportnum, svcnum, graphnum, imported, thumbnail', #no need to load old content
'order_by' => 'ORDER BY graphnum',
});
- if (@oldpages) {
- #if pages are recent enough, do nothing and return
- if ($oldpages[0]->imported > $self->exptime($now)) {
- $job->update_statustext(100);
- return '';
- }
- #delete old pages
- foreach my $oldpage (@oldpages) {
- my $error = $oldpage->delete;
- if ($error) {
- $dbh->rollback if $oldAutoCommit;
- die $error;
+
+ # if all existing pages are recent enough, do nothing and return
+ # (won't detect newly introduced graphs, but they can wait for next run)
+ my $uptodate = 0;
+ if (keys %oldpages) {
+ $uptodate = 1;
+ foreach my $oldpage (keys %oldpages) {
+ if ($oldpages{$oldpage}->imported <= $self->exptime($now)) {
+ $uptodate = 0;
+ last;
}
}
}
+ if ($uptodate) {
+ $job->update_statustext(100);
+ return '';
+ }
$job->update_statustext(30);
# get list of graphs for this svc from cacti server
my $cmd = $php
- . $self->option('script_path')
+ . trailslash($self->option('script_path'))
. q(freeside_cacti.php --get-graphs --ip=')
. $svc->ip_addr
. q(');
+ $cmd .= q( --include-path=') . $self->option('include_path') . q(')
+ if $self->option('include_path');
my @graphs = map { [ split(/\t/,$_) ] }
split(/\n/, ssh_cmd(
'host' => $self->machine,
'rsh' => 'ssh',
'verbose' => 1,
'recursive' => 1,
- 'source' => $self->option('graphs_path'),
+ 'quote-src' => 1,
+ 'quote-dst' => 1,
+ 'source' => trailslash($self->option('graphs_path')),
'dest' => $cachedir,
'include' => [
(map { q('**graph_).${$_}[0].q(*.png') } @graphs),
],
});
#don't know why a regular $rsync->exec isn't doing includes right, but this does
- my $error = system(join(' ',@{$rsync->getcmd()}));
- die "rsync failed with exit status $error" if $error;
+ my $rscmd = join(' ',@{$rsync->getcmd()});
+ my $error = system($rscmd);
+ die "rsync ($rscmd) failed with exit status $error" if $error;
$job->update_statustext(50);
if (-e $thumbfile) {
if ( stat($thumbfile)->size() < $maxgraph ) {
$nographs = 0;
+ my $thumbnail = img_tag($thumbfile);
# add graph to main file
my $graphhead = q(<H3>) . $$graph[1] . q(</H3>);
$svchtml .= $graphhead;
- $svchtml .= anchor_tag( $svcnum, $$graph[0], img_tag($thumbfile) );
+ $svchtml .= anchor_tag( $svcnum, $$graph[0], $thumbnail );
# create graph details file
my $graphhtml = $svchead . $graphhead;
my $nodetail = 1;
my $j = 1;
+ # no easy way to tell what detail graphs should exist,
+ # and don't want detail graphs that are out of sync with thumbnail,
+ # so just use what we can find
while (-e (my $graphfile = $cachedir.'graphs/graph_'.$$graph[0].'_'.$j.'.png')) {
if ( stat($graphfile)->size() < $maxgraph ) {
$nodetail = 0;
}
$graphhtml .= '<P>No detail graphs to display for this graph</P>'
if $nodetail;
+ #delete old detail page
+ if ($oldpages{$$graph[0]}) {
+ $error = $oldpages{$$graph[0]}->delete;
+ if ($error) {
+ $dbh->rollback if $oldAutoCommit;
+ die $error;
+ }
+ }
+ #insert new detail page
my $newobj = new FS::cacti_page {
'exportnum' => $self->exportnum,
'svcnum' => $svcnum,
'graphnum' => $$graph[0],
'imported' => $now,
'content' => $graphhtml,
+ 'thumbnail' => $thumbnail,
};
$error = $newobj->insert;
if ($error) {
die $error;
}
} else {
- warn "File $thumbfile is too large, skipping";
+ $svchtml .= qq(<P STYLE="color: #FF0000">File $thumbfile is too large, skipping</P>);
}
unlink($thumbfile);
} else {
- warn "File $thumbfile does not exist, skipping";
+ # try to use old page for this graph
+ if ($oldpages{$$graph[0]} && $oldpages{$$graph[0]}->thumbnail) {
+ $nographs = 0;
+ # add old graph to main file
+ my $graphhead = q(<H3>) . $$graph[1] . q(</H3>);
+ $svchtml .= $graphhead;
+ $svchtml .= qq(<P STYLE="color: #FF0000">Current graphs unavailable; using previously imported data.</P>);
+ $svchtml .= anchor_tag( $svcnum, $$graph[0], $oldpages{$$graph[0]}->thumbnail );
+ } else {
+ $svchtml .= qq(<P STYLE="color: #FF0000">Error loading graph: $$graph[0]</P>);
+ }
}
+ # remove old page from hash even if it is being reused,
+ # remaining entries in hash will be deleted from database below
+ delete $oldpages{$$graph[0]} if $oldpages{$$graph[0]};
$job->update_statustext(49 + int($i / @graphs) * 50);
}
$svchtml .= '<P>No graphs to display for this service</P>'
if $nographs;
+ # delete remaining old pages, including svc index
+ foreach my $oldpage (keys %oldpages) {
+ $error = $oldpages{$oldpage}->delete;
+ if ($error) {
+ $dbh->rollback if $oldAutoCommit;
+ die $error;
+ }
+ }
+ # insert new index page for svc
my $newobj = new FS::cacti_page {
'exportnum' => $self->exportnum,
'svcnum' => $svcnum,
'graphnum' => '',
'imported' => $now,
'content' => $svchtml,
+ 'thumbnail' => '',
};
$error = $newobj->insert;
if ($error) {
return $output;
}
+#there's probably a better place to put this?
+#makes sure there's a trailing slash between/after input
+#doesn't add leading slashes
+sub trailslash {
+ my @paths = @_;
+ my $out = '';
+ foreach my $path (@paths) {
+ $out .= $path;
+ $out .= '/' unless $out =~ /\/$/;
+ }
+ return $out;
+}
+
=head1 METHODS
=over 4
Jonathan Prykop
jonathan@freeside.biz
-=head1 LICENSE AND COPYRIGHT
-
-Copyright 2015 Freeside Internet Services
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation.
-
=cut
1;