[freeside-commits] branch master updated. f715c23517292a11330ab241fb13221fd89ffc37

Jonathan Prykop jonathan at 420.am
Thu Apr 30 15:29:14 PDT 2015


The branch, master has been updated
       via  f715c23517292a11330ab241fb13221fd89ffc37 (commit)
      from  3acf33a87b4e8ebaac08652177d79b22721e2690 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit f715c23517292a11330ab241fb13221fd89ffc37
Author: Jonathan Prykop <jonathan at freeside.biz>
Date:   Thu Apr 30 17:28:36 2015 -0500

    RT#18834: Cacti integration [added graph generation]

diff --git a/FS/FS/part_export/cacti.pm b/FS/FS/part_export/cacti.pm
index abeb5e4..eff6c52 100644
--- a/FS/FS/part_export/cacti.pm
+++ b/FS/FS/part_export/cacti.pm
@@ -50,16 +50,42 @@ tie my %options, 'Tie::IxHash',
                            default => '5' },
   'max_graph_size'    => { label   => 'Maximum size per graph (MB)',
                            default => '5' },
-#  'delete_graphs'     => { label   => 'Delete associated graphs and data sources when unprovisioning', 
-#                           type    => 'checkbox',
-#                         },
+  'delete_graphs'     => { label   => 'Delete associated graphs and data sources when unprovisioning', 
+                           type    => 'checkbox',
+                         },
+  'cacti_graph_template_id'  => { 
+    'label'    => 'Graph Template',
+    'type'     => 'custom',
+    'multiple' => 1,
+  },
+  'cacti_snmp_query_id'      => { 
+    'label'    => 'SNMP Query ID',
+    'type'     => 'custom',
+    'multiple' => 1,
+  },
+  'cacti_snmp_query_type_id' => { 
+    'label'    => 'SNMP Query Type ID',
+    'type'     => 'custom',
+    'multiple' => 1,
+  },
+  'cacti_snmp_field'         => { 
+    'label'    => 'SNMP Field',
+    'type'     => 'custom',
+    'multiple' => 1,
+  },
+  'cacti_snmp_value'         => { 
+    'label'    => 'SNMP Value',
+    'type'     => 'custom',
+    'multiple' => 1,
+  },
 ;
 
 %info = (
-  'svc'             => 'svc_broadband',
-  'desc'            => 'Export service to cacti server, for svc_broadband services',
-  'options'         => \%options,
-  'notes'           => <<'END',
+  'svc'                  => 'svc_broadband',
+  'desc'                 => 'Export service to cacti server, for svc_broadband services',
+  'post_config_element'  => '/edit/elements/part_export/cacti.html',
+  'options'              => \%options,
+  'notes'                => <<'END',
 Add service to cacti upon provisioning, for broadband services.<BR>
 See <A HREF="http://www.freeside.biz/mediawiki/index.php/Freeside:4:Documentation:Cacti#Connecting_Cacti_To_Freeside">documentation</A> for details.
 END
@@ -75,8 +101,23 @@ sub _export_insert {
 
 sub _export_delete {
   my ($self, $svc_broadband) = @_;
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
+  foreach my $page (qsearch('cacti_page',{ svcnum => $svc_broadband->svcnum })) {
+    my $error = $page->delete;
+    if ($error) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
   my ($q,$error) = _delete_queue($self, $svc_broadband);
-  return $error;
+  if ($error) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error;
+  }
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+  return '';
 }
 
 sub _export_replace {
@@ -133,6 +174,7 @@ sub _insert_queue {
 	'svc_desc'    => $svc_broadband->description,
     'contact'     => $svc_broadband->cust_main->contact,
     'svcnum'      => $svc_broadband->svcnum,
+    'self'        => $self
   );
   return ($queue,$error);
 }
@@ -148,7 +190,7 @@ sub _delete_queue {
     'user'          => $self->option('user'),
     'hostname'      => $svc_broadband->ip_addr,
     'script_path'   => $self->option('script_path'),
-#    'delete_graphs' => $self->option('delete_graphs'),
+    'delete_graphs' => $self->option('delete_graphs'),
   );
   return ($queue,$error);
 }
@@ -157,6 +199,7 @@ sub _delete_queue {
 
 sub ssh_insert {
   my %opt = @_;
+  my $self = $opt{'self'};
 
   # Option validation
   die "Non-numerical Host Template ID, check export configuration\n"
@@ -169,7 +212,10 @@ sub ssh_insert {
   $desc =~ s/\$ip_addr/$opt{'hostname'}/g;
   $desc =~ s/\$description/$opt{'svc_desc'}/g;
   $desc =~ s/\$contact/$opt{'contact'}/g;
-  $desc =~ s/'/'\\''/g;
+#for some reason, device names with apostrophes fail to export graphs in Cacti
+#just removing them for now, someday maybe dig to figure out why
+#  $desc =~ s/'/'\\''/g;
+  $desc =~ s/'//g;
   my $cmd = $php
           . $opt{'script_path'} 
           . q(add_device.php --description=')
@@ -194,51 +240,94 @@ sub ssh_insert {
          . $id;
     $response = ssh_cmd(%opt, 'command' => $cmd);
     unless ( $response =~ /Added Node node-id: \((\d+)\)/ ) {
-      die "Error adding host to tree: $response";
+      die "Host added, but error adding host to tree: $response";
     }
   }
 
-#  # Get list of graph templates for new id
-#  $cmd = $php
-#       . $opt{'script_path'} 
-#       . q(freeside_cacti.php --get-graph-templates --host-template=)
-#       . $opt{'template_id'};
-#  my @gtids = split(/\n/,ssh_cmd(%opt, 'command' => $cmd));
-#  die "No graphs configured for host template"
-#    unless @gtids;
-#
-#  # Create graphs
-#  foreach my $gtid (@gtids) {
-#
-#    # sanity checks, should never happen
-#    next unless $gtid;
-#    die "Bad graph template: $gtid"
-#      unless $gtid =~ /^\d+$/;
-#
-#    # create the graph
-#    $cmd = $php
-#         . $opt{'script_path'}
-#         . q(add_graphs.php --graph-type=cg --graph-template-id=)
-#         . $gtid
-#         . q( --host-id=)
-#         . $id;
-#    $response = ssh_cmd(%opt, 'command' => $cmd);
-#    die "Error creating graph $gtid: $response"
-#      unless $response =~ /Graph Added - graph-id: \((\d+)\)/;
-#    my $gid = $1;
-#
-#    # add the graph to the tree
-#    $cmd = $php
-#         . $opt{'script_path'}
-#         . q(add_tree.php --type=node --node-type=graph --tree-id=)
-#         . $opt{'tree_id'}
-#         . q( --graph-id=)
-#         . $gid;
-#    $response = ssh_cmd(%opt, 'command' => $cmd);
-#    die "Error adding graph $gid to tree: $response"
-#      unless $response =~ /Added Node/;
-#
-#  } #foreach $gtid
+  # Get list of graph templates for new id
+  $cmd = $php
+       . $opt{'script_path'} 
+       . q(freeside_cacti.php --get-graph-templates --host-template=)
+       . $opt{'template_id'};
+  my $ginfo = { map { $_ ? ($_ => undef) : () } split(/\n/,ssh_cmd(%opt, 'command' => $cmd)) };
+
+  # Add extra config info
+  my @xtragid = split("\n", $self->option('cacti_graph_template_id'));
+  my @query_id = split("\n", $self->option('cacti_snmp_query_id'));
+  my @query_type_id = split("\n", $self->option('cacti_snmp_query_type_id'));
+  my @snmp_field = split("\n", $self->option('cacti_snmp_field'));
+  my @snmp_value = split("\n", $self->option('cacti_snmp_value'));
+  for (my $i = 0; $i < @xtragid; $i++) {
+    my $gtid = $xtragid[$i];
+    $ginfo->{$gtid} ||= [];
+    push(@{$ginfo->{$gtid}},{
+      'gtid'          => $gtid,
+      'query_id'      => $query_id[$i],
+      'query_type_id' => $query_type_id[$i],
+      'snmp_field'    => $snmp_field[$i],
+      'snmp_value'    => $snmp_value[$i],
+    });
+  }
+
+  my @gdefs = map {
+    ref($ginfo->{$_}) ? @{$ginfo->{$_}} : {'gtid' => $_}
+  } keys %$ginfo;
+  warn "Host ".$opt{'hostname'}." exported to cacti, but no graphs configured"
+    unless @gdefs;
+
+  # Create graphs
+  my $gerror = '';
+  foreach my $gdef (@gdefs) {
+    # validate graph info
+    my $gtid = $gdef->{'gtid'};
+    next unless $gtid;
+    $gerror .= " Bad graph template: $gtid"
+      unless $gtid =~ /^\d+$/;
+    my $isds = $gdef->{'query_id'} 
+            || $gdef->{'query_type_id'} 
+            || $gdef->{'snmp_field'} 
+            || $gdef->{'snmp_value'};
+    if ($isds) {
+      $gerror .= " Bad SNMP Query Id: " . $gdef->{'query_id'}
+        unless $gdef->{'query_id'} =~ /^\d+$/;
+      $gerror .= " Bad SNMP Query Type Id: " . $gdef->{'query_type_id'}
+        unless $gdef->{'query_type_id'} =~ /^\d+$/;
+      $gerror .= " SNMP Field cannot contain apostrophe"
+        if $gdef->{'snmp_field'} =~ /'/;
+      $gerror .= " SNMP Value cannot contain apostrophe"
+        if $gdef->{'snmp_value'} =~ /'/;
+    }
+    next if $gerror;
+
+    # create the graph
+    $cmd = $php
+         . $opt{'script_path'}
+         . q(add_graphs.php --graph-type=)
+         . ($isds ? 'ds' : 'cg')
+         . q( --graph-template-id=)
+         . $gtid
+         . q( --host-id=)
+         . $id;
+    if ($isds) {
+      $cmd .= q( --snmp-query-id=)
+           .  $gdef->{'query_id'}
+           .  q( --snmp-query-type-id=)
+           .  $gdef->{'query_type_id'}
+           .  q( --snmp-field=')
+           .  $gdef->{'snmp_field'}
+           .  q(' --snmp-value=')
+           .  $gdef->{'snmp_value'}
+           .  q(');
+    }
+    $response = ssh_cmd(%opt, 'command' => $cmd);
+    #might be more than one graph added, just testing success
+    $gerror .= "Error creating graph $gtid: $response"
+      unless $response =~ /Graph Added - graph-id: \((\d+)\)/;
+
+  } #foreach $gtid
+
+  # job fails, but partial export may have occurred
+  die $gerror . " Partial export occurred\n" if $gerror;
 
   return '';
 }
@@ -250,8 +339,8 @@ sub ssh_delete {
           . q(freeside_cacti.php --drop-device --ip=')
           . $opt{'hostname'}
           . q(');
-#  $cmd .= q( --delete-graphs)
-#    if $opt{'delete_graphs'};
+  $cmd .= q( --delete-graphs)
+    if $opt{'delete_graphs'};
   my $response = ssh_cmd(%opt, 'command' => $cmd);
   die "Error removing from cacti: " . $response
     if $response;
@@ -368,42 +457,43 @@ sub process_graphs {
   for (my $i = 0; $i <= $#graphs; $i++) {
     my $graph = $graphs[$i];
     my $thumbfile = $cachedir . 'graphs/thumb_' . $$graph[0] . '.png';
-    if (
-      (-e $thumbfile) && 
-      ( stat($thumbfile)->size() < $maxgraph )
-    ) {
-      $nographs = 0;
-      # add graph to main file
-      my $graphhead = q(<H3>) . $$graph[1] . q(</H3>);
-      $svchtml .= $graphhead;
-      $svchtml .= anchor_tag( $svcnum, $$graph[0], img_tag($thumbfile) );
-      # create graph details file
-      my $graphhtml = $svchead . $graphhead;
-      my $nodetail = 1;
-      my $j = 1;
-      while (-e (my $graphfile = $cachedir.'graphs/graph_'.$$graph[0].'_'.$j.'.png')) {
-        if ( stat($graphfile)->size() < $maxgraph ) {
-          $nodetail = 0;
-          $graphhtml .= img_tag($graphfile);
+    if (-e $thumbfile) {
+      if ( stat($thumbfile)->size() < $maxgraph ) {
+        $nographs = 0;
+        # add graph to main file
+        my $graphhead = q(<H3>) . $$graph[1] . q(</H3>);
+        $svchtml .= $graphhead;
+        $svchtml .= anchor_tag( $svcnum, $$graph[0], img_tag($thumbfile) );
+        # create graph details file
+        my $graphhtml = $svchead . $graphhead;
+        my $nodetail = 1;
+        my $j = 1;
+        while (-e (my $graphfile = $cachedir.'graphs/graph_'.$$graph[0].'_'.$j.'.png')) {
+          if ( stat($graphfile)->size() < $maxgraph ) {
+            $nodetail = 0;
+            $graphhtml .= img_tag($graphfile);
+          }
+          unlink($graphfile);
+          $j++;
+        }
+        $graphhtml .= '<P>No detail graphs to display for this graph</P>'
+          if $nodetail;
+        my $newobj = new FS::cacti_page {
+          'exportnum' => $self->exportnum,
+          'svcnum'    => $svcnum,
+          'graphnum'  => $$graph[0],
+          'imported'  => $now,
+          'content'   => $graphhtml,
+        };
+        $error = $newobj->insert;
+        if ($error) {
+          $dbh->rollback if $oldAutoCommit;
+          die $error;
         }
-        $j++;
-      }
-      $graphhtml .= '<P>No detail graphs to display for this graph</P>'
-        if $nodetail;
-      my $newobj = new FS::cacti_page {
-        'exportnum' => $self->exportnum,
-        'svcnum'    => $svcnum,
-        'graphnum'  => $$graph[0],
-        'imported'  => $now,
-        'content'   => $graphhtml,
-      };
-      $error = $newobj->insert;
-      if ($error) {
-        $dbh->rollback if $oldAutoCommit;
-        die $error;
       }
+      unlink($thumbfile);
     }
-    $job->update_statustext(49 + int($i / $#graphs) * 50);
+    $job->update_statustext(49 + int($i / @graphs) * 50);
   }
   $svchtml .= '<P>No graphs to display for this service</P>'
     if $nographs;
@@ -452,7 +542,7 @@ sub ssh_cmd {
   my $ssh = Net::OpenSSH->new($opt->{'user'}.'@'.$opt->{'host'});
   die "Couldn't establish SSH connection: ". $ssh->error if $ssh->error;
   my ($output, $errput) = $ssh->capture2($opt->{'command'});
-  die "Error running SSH command: ". $ssh->error if $ssh->error;
+  die "Error running SSH command: ". $opt->{'command'}. ' ERROR: ' . $ssh->error if $ssh->error;
   die $errput if $errput;
   return $output;
 }
diff --git a/bin/freeside_cacti.php b/bin/freeside_cacti.php
index 0a9ee9c..9f8e4dd 100755
--- a/bin/freeside_cacti.php
+++ b/bin/freeside_cacti.php
@@ -39,18 +39,15 @@ but keeping commented out code for potential future development.
 include(dirname(__FILE__)."/../site/include/global.php");
 include_once($config["base_path"]."/lib/api_device.php");
 include_once($config["base_path"]."/lib/api_automation_tools.php");
-
-/*
 include_once($config["base_path"]."/lib/api_data_source.php");
 include_once($config["base_path"]."/lib/api_graph.php");
 include_once($config["base_path"]."/lib/functions.php");
-*/
 
 /* process calling arguments */
 $action = '';
 $ip = '';
 $host_template = '';
-// $delete_graphs = FALSE;
+$delete_graphs = FALSE;
 $parms = $_SERVER["argv"];
 array_shift($parms);
 if (sizeof($parms)) {
@@ -67,21 +64,19 @@ if (sizeof($parms)) {
         case "--get-device":
 			$action = 'get-device';
             break;
+*/
         case "--get-graph-templates":
 			$action = 'get-graph-templates';
             break;
-*/
 		case "--ip":
 			$ip = trim($value);
 			break;
 		case "--host-template":
 			$host_template = trim($value);
 			break;
-/*
 		case "--delete-graphs":
 			$delete_graphs = TRUE;
 			break;
-*/
 		case "--version":
 		case "-V":
 		case "-H":
@@ -102,7 +97,6 @@ case "get-graphs":
 	break;
 case "drop-device":
 	$host_id = host_id($ip);
-/*
 	if ($delete_graphs) {
 		// code copied & pasted from version 0.8.8a
         // cacti/site/lib/host.php and cacti/site/graphs.php 
@@ -126,7 +120,6 @@ case "drop-device":
 			}
 		}
 	}
-*/
 	api_device_remove($host_id);
 	if (host_id($ip,1)) {
 		die("Failed to remove hostname $ip");
@@ -136,6 +129,7 @@ case "drop-device":
 case "get-device":
 	echo host_id($ip);
 	exit(0);
+*/
 case "get-graph-templates":
 	if (!$host_template) {
 		die("No host template specified");
@@ -148,7 +142,6 @@ case "get-graph-templates":
 		exit(0);
 	}
 	die("No graph templates associated with this host template");
-*/
 default:
 	die("Specified action not found, contact a developer");
 }
diff --git a/httemplate/browse/part_export.cgi b/httemplate/browse/part_export.cgi
index 1f835d7..af988d3 100755
--- a/httemplate/browse/part_export.cgi
+++ b/httemplate/browse/part_export.cgi
@@ -66,7 +66,7 @@ function part_export_areyousure(href) {
 %           if ( $group ) {
 %             my @values = split("\n", $opt{$optname});
 %             $multiples{$group} ||= [];
-%             push @{ $multiples{$group} }, [ $optname, @values ] if @values;
+%             push @{ $multiples{$group} }, [ $def->{label} || $optname, @values ] if @values;
 %             delete $opt{$optname};
 %           } elsif (length($opt{$optname})) { # the normal case
 %             my $value = $opt{$optname};
diff --git a/httemplate/edit/elements/part_export/cacti.html b/httemplate/edit/elements/part_export/cacti.html
new file mode 100644
index 0000000..9e4a8ec
--- /dev/null
+++ b/httemplate/edit/elements/part_export/cacti.html
@@ -0,0 +1,42 @@
+<table bgcolor="#cccccc" border=0 cellspacing=3>
+<TR>
+  <TH>Graph Template ID</TH>
+  <TH>SNMP Query ID</TH>
+  <TH>SNMP Query Type ID</TH>
+  <TH>SNMP Field</TH>
+  <TH>SNMP Value</TH>
+</TR>
+<TR id="mytemplate">
+  <TD><INPUT TYPE="text" NAME="graph_template_id" ID="graph_template_id"></TD>
+  <TD><INPUT TYPE="text" NAME="snmp_query_id" ID="snmp_query_id"></TD>
+  <TD><INPUT TYPE="text" NAME="snmp_query_type_id" ID="snmp_query_type_id"></TD>
+  <TD><INPUT TYPE="text" NAME="snmp_field" ID="snmp_field"></TD>
+  <TD><INPUT TYPE="text" NAME="snmp_value" ID="snmp_value"></TD>
+</TR>
+<& /elements/auto-table.html,
+  template_row  => 'mytemplate',
+  fieldorder    => ['graph_template_id','snmp_query_id','snmp_query_type_id','snmp_field','snmp_value'],
+  data          => \@data,
+  table         => 'cacti',
+&>
+</table>
+<INPUT TYPE="hidden" name="multi_options" value="<% $multiopts %>">
+<%init>
+my %opt = @_;
+my $part_export = $opt{part_export} || die "No part_export specified";
+
+my @fields = ('cacti_graph_template_id','cacti_snmp_query_id','cacti_snmp_query_type_id','cacti_snmp_field','cacti_snmp_value');
+my $multiopts = join(',', at fields);
+my @byfield = map {
+  [ split("\n", $part_export->option($_)) ]
+} @fields;
+my @data;
+for (my $i = 0; $i < @{$byfield[0]}; $i++) {
+  my @thisrow;
+  for (my $j = 0; $j < @byfield; $j++) {
+    push(@thisrow,$byfield[$j][$i]);
+  }
+  push(@data,\@thisrow);
+}
+
+</%init>
diff --git a/httemplate/edit/part_export.cgi b/httemplate/edit/part_export.cgi
index 0e53e29..3820931 100644
--- a/httemplate/edit/part_export.cgi
+++ b/httemplate/edit/part_export.cgi
@@ -183,6 +183,10 @@ my $widget = new HTML::Widgets::SelectLayers(
                       ? $optinfo->{default}
                       : ''
                     );
+
+      #handle these with post_config_element
+      next if $type eq 'custom';
+
       if ( $type eq 'title' ) {
         $html .= qq!<TR><TH COLSPAN=1 ALIGN="right"><FONT SIZE="+1">! .
                  $label .
@@ -283,6 +287,17 @@ my $widget = new HTML::Widgets::SelectLayers(
 
     $html .= '</TABLE>';
 
+    # false laziness with config_element above
+    # create 'post_config_element' to generate the whole layer with a Mason component
+    if ( my $include = $exports->{$layer}{post_config_element} ) {
+      # might need to adjust the scope of  this at some point
+      $html .= $m->scomp($include, 
+        part_export => $part_export,
+        layer       => $layer,
+        export_info => $exports->{$layer}
+      );
+    }
+
     $html .= '<INPUT TYPE="hidden" NAME="options" VALUE="'.
              join(',', keys %{$exports->{$layer}{options}} ). '">';
 

-----------------------------------------------------------------------

Summary of changes:
 FS/FS/part_export/cacti.pm                      |  266 +++++++++++++++--------
 bin/freeside_cacti.php                          |   13 +-
 httemplate/browse/part_export.cgi               |    2 +-
 httemplate/edit/elements/part_export/cacti.html |   42 ++++
 httemplate/edit/part_export.cgi                 |   15 ++
 5 files changed, 239 insertions(+), 99 deletions(-)
 create mode 100644 httemplate/edit/elements/part_export/cacti.html




More information about the freeside-commits mailing list