d55bfc35bccfb885169658f662e531b36b01601b
[freeside.git] / FS / FS / NetworkMonitoringSystem / Torrus_Internal.pm
1 package FS::NetworkMonitoringSystem::Torrus_Internal;
2
3 use strict;
4 #use vars qw( $DEBUG $me );
5 use Fcntl qw(:flock);
6 use IO::File;
7 use File::Slurp qw(slurp);
8 use Date::Format;
9 use XML::Simple;
10 use FS::svc_port;
11 use FS::Record qw(qsearch);
12 use Torrus::ConfigTree;
13
14 #$DEBUG = 0;
15 #$me = '[FS::NetworkMonitoringSystem::Torrus_Internal]';
16
17 our $lock;
18 our $lockfile = '/usr/local/etc/torrus/discovery/FSLOCK';
19 our $ddxfile  = '/usr/local/etc/torrus/discovery/routers.ddx';
20
21 sub new {
22     my $class = shift;
23     my $self = {};
24     bless $self, $class;
25     return $self;
26 }
27
28 sub ddx2hash {
29     my $self = shift;
30     my $ddx_xml = slurp($ddxfile);
31     my $xs = new XML::Simple(RootName=> undef, SuppressEmpty => '', 
32                                 ForceArray => 1, );
33     return $xs->XMLin($ddx_xml);
34 }
35
36 sub get_router_serviceids {
37     my $self = shift;
38     my $router = shift;
39     my $find_serviceid = shift;
40     my $found_serviceid = 0;
41     my $ddx_hash = $self->ddx2hash;
42     if($ddx_hash->{host}){
43         my @hosts = @{$ddx_hash->{host}};
44         foreach my $host ( @hosts ) {
45             my $param = $host->{param};
46             if($param && $param->{'snmp-host'} 
47                       && (!$router || $param->{'snmp-host'}->{'value'} eq $router)
48                       && $param->{'RFC2863_IF_MIB::external-serviceid'}) {
49                 my $serviceids = $param->{'RFC2863_IF_MIB::external-serviceid'}->{'content'};
50                 my %hash = ();
51                 if($serviceids) {
52                     my @serviceids = split(',',$serviceids);
53                     foreach my $serviceid ( @serviceids ) {
54                         $serviceid =~ s/^\s+|\s+$//g;
55                         my @s = split(':',$serviceid);
56                         next unless scalar(@s) == 4;
57                         $hash{$s[1]} = $s[0] if $router;
58                         if ($find_serviceid && $find_serviceid eq $s[0]) {
59                             $hash{$param->{'snmp-host'}->{'value'}} = $s[1];
60                             $found_serviceid = 1;
61                         }
62                     }
63                 }
64                 return \%hash if ($router || $found_serviceid);
65             }
66         }
67     }
68     '';
69 }
70
71 sub port_graphs_link {
72     # hardcoded for 'main' tree for now 
73     my $self = shift;
74     my $serviceid = shift;
75     my $hash = $self->get_router_serviceids(undef,$serviceid);
76     my @keys = keys %$hash; # yeah this is weird...
77     my $host = $keys[0];
78     my $iface = $hash->{$keys[0]};
79     my $config_tree = new Torrus::ConfigTree( -TreeName => 'main' );
80     my $token = $config_tree->token("/Routers/$host/Interface_Counters/$iface/InOut_bps");
81     return $Torrus::Freeside::FSURL."/torrus/main?token=$token";
82 }
83
84 sub find_svc {
85     my $self = shift;
86     my $serviceid = shift;
87     return '' unless $serviceid =~ /^[0-9A-Za-z_\-.\\\/ ]+$/;
88   
89     my @svc_port = qsearch('svc_port', { 'serviceid' => $serviceid });
90     return '' unless scalar(@svc_port);
91
92     # for now it's like this, later on just change to qsearchs
93
94     return $svc_port[0];
95 }
96
97 sub add_router {
98   my($self, $ip) = @_;
99
100   my $newhost = 
101     qq(  <host>\n).
102     qq(    <param name="snmp-host" value="$ip"/>\n).
103     qq(  </host>\n);
104
105   my $ddx = $self->_torrus_loadddx;
106
107   $ddx =~ s{(</snmp-discovery>)}{$newhost$1};
108
109   $self->_torrus_newddx($ddx);
110
111 }
112
113 sub add_interface {
114   my($self, $router_ip, $interface, $serviceid ) = @_;
115
116   $interface =~ s(\/)(_)g;
117
118   #should just use a proper XML parser huh
119
120   my $newline = "     $serviceid:$interface:Both:main,";
121
122   my @ddx = split(/\n/, $self->_torrus_loadddx);
123   my $new = '';
124
125   my $added = 0;
126
127   while ( my $line = shift(@ddx) ) {
128     $new .= "$line\n";
129     next unless $line =~ /^\s*<param\s+name="snmp-host"\s+value="$router_ip"\/?>/i;
130
131     while ( my $hostline = shift(@ddx) ) {
132       $new .= "$hostline\n" unless $hostline =~ /^\s+<\/host>\s*/i;
133       if ( $hostline =~ /^\s*<param name="RFC2863_IF_MIB::external-serviceid"\/?>/i ) {
134
135         while ( my $paramline = shift(@ddx) ) {
136           if ( $paramline =~ /^\s*<\/param>/ ) {
137             $new .= "$newline\n$paramline";
138             last; #paramline
139           } else {
140             $new .= $paramline;
141           }
142         }
143
144         $added++;
145
146       } elsif ( $hostline =~ /^\s+<\/host>\s*/i ) {
147         unless ( $added ) {
148           $new .= 
149             qq(   <param name="RFC2863_IF_MIB::external-serviceid">\n).
150             qq(     $newline\n").
151             qq(   </param>\n);
152         }
153         $new .= $hostline;
154         last; #hostline
155       }
156  
157     }
158
159   }
160
161   $self->_torrus_newddx($new);
162
163 }
164
165 sub _torrus_lock {
166   $lock = new IO::File ">>$lockfile" or die $!;
167   flock($lock, LOCK_EX);
168 }
169
170 sub _torrus_unlock {
171   flock($lock, LOCK_UN);
172   close $lock;
173 }
174
175 sub _torrus_loadddx {
176   my($self) = @_;
177   $self->_torrus_lock;
178   return slurp($ddxfile);
179 }
180
181 sub _torrus_newddx {
182   my($self, $ddx) = @_;
183
184   my $new = new IO::File ">$ddxfile.new"
185     or die "can't write to $ddxfile.new: $!";
186   print $new $ddx;
187   close $new;
188
189   # `date ...` created file names with weird chars in them
190   my $tmpname = $ddxfile . Date::Format::time2str('%Y%m%d%H%M%S',time);
191   rename("$ddxfile", $tmpname) or die $!;
192   rename("$ddxfile.new", $ddxfile) or die $!;
193
194   $self->_torrus_reload;
195 }
196
197 sub _torrus_reload {
198   my($self) = @_;
199
200   #i should have better error checking
201
202   system('torrus', 'devdiscover', "--in=$ddxfile");
203
204   system('torrus', 'compile', '--tree=main'); # , '--verbose'
205
206   $self->_torrus_unlock;
207
208 }
209
210 1;