per-agent configuration of batch processors, #71837
[freeside.git] / torrus / perllib / Torrus / DevDiscover / Foundry.pm
1 #  Copyright (C) 2008 Roman Hochuli
2 #  Copyright (C) 2010 Stanislav Sinyagin
3 #
4 #  This program is free software; you can redistribute it and/or modify
5 #  it under the terms of the GNU General Public License as published by
6 #  the Free Software Foundation; either version 2 of the License, or
7 #  (at your option) any later version.
8 #
9 #  This program is distributed in the hope that it will be useful,
10 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 #  GNU General Public License for more details.
13 #
14 #  You should have received a copy of the GNU General Public License
15 #  along with this program; if not, write to the Free Software
16 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
17
18 # $Id: Foundry.pm,v 1.1 2010-12-27 00:03:48 ivan Exp $
19 # Roman Hochuli <roman@hochu.li>
20
21 # Common Foundry MIBs, supported by IronWare-Devices
22
23 package Torrus::DevDiscover::Foundry;
24
25 use strict;
26 use Torrus::Log;
27
28
29 $Torrus::DevDiscover::registry{'Foundry'} = {
30     'sequence'     => 500,
31     'checkdevtype' => \&checkdevtype,
32     'discover'     => \&discover,
33     'buildConfig'  => \&buildConfig
34     };
35
36
37 our %oiddef =
38     (
39      # FOUNDRY-SN-ROOT-MIB
40      'fdry'                              => '1.3.6.1.4.1.1991',
41      
42      # FOUNDRY-SN-AGENT-MIB
43      'fdrySnChasSerNum'                  => '1.3.6.1.4.1.1991.1.1.1.1.2.0',
44      'fdrySnChasGen'                     => '1.3.6.1.4.1.1991.1.1.1.1.13',
45      'fdrySnChasIdNumber'                => '1.3.6.1.4.1.1991.1.1.1.1.17.0',
46      'fdrySnChasArchitectureType'        => '1.3.6.1.4.1.1991.1.1.1.1.25.0',
47      'fdrySnChasProductType'             => '1.3.6.1.4.1.1991.1.1.1.1.26.0',
48
49      # FOUNDRY-SN-AGENT-MIB
50      'fdrySnChasActualTemperature'       => '1.3.6.1.4.1.1991.1.1.1.1.18.0',
51      'fdrySnChasWarningTemperature'      => '1.3.6.1.4.1.1991.1.1.1.1.19.0',
52      'fdrySnChasShutdownTemperature'     => '1.3.6.1.4.1.1991.1.1.1.1.20.0',
53      'fdrySnAgImgVer'                    => '1.3.6.1.4.1.1991.1.1.2.1.11',
54      'fdrySnAgentTempTable'              => '1.3.6.1.4.1.1991.1.1.2.13.1',
55      'fdrySnAgentTempSensorDescr'        => '1.3.6.1.4.1.1991.1.1.2.13.1.1.3',
56      'fdrySnAgentTempValue'              => '1.3.6.1.4.1.1991.1.1.2.13.1.1.4',
57
58      # FOUNDRY-SN-AGENT-MIB
59      'fdrySnAgGblCpuUtilData'            => '1.3.6.1.4.1.1991.1.1.2.1.35',
60      'fdrySnAgGblCpuUtil1SecAvg'         => '1.3.6.1.4.1.1991.1.1.2.1.50',
61      'fdrySnAgGblCpuUtil5SecAvg'         => '1.3.6.1.4.1.1991.1.1.2.1.51',
62      'fdrySnAgGblCpuUtil1MinAvg'         => '1.3.6.1.4.1.1991.1.1.2.1.52',
63      'fdrySnAgentCpuUtilValue'           => '1.3.6.1.4.1.1991.1.1.2.11.1.1.4',
64      'fdrySnAgentCpuUtil100thPercent'    => '1.3.6.1.4.1.1991.1.1.2.11.1.1.6',
65
66      # FOUNDRY-SN-AGENT-MIB
67      'fdrySnAgentBrdTbl'                 => '1.3.6.1.4.1.1991.1.1.2.2.1.1',
68      'fdrySnAgentBrdMainBrdDescription'  => '1.3.6.1.4.1.1991.1.1.2.2.1.1.2',
69      'fdrySnAgentBrdMainPortTotal'       => '1.3.6.1.4.1.1991.1.1.2.2.1.1.4',
70      'fdrySnAgentBrdModuleStatus'        => '1.3.6.1.4.1.1991.1.1.2.2.1.1.12',
71      # Not listed in FOUNDRY-SN-AGENT-MIB, but in release notes
72      'fdrySnAgentBrdMemoryTotal'         => '1.3.6.1.4.1.1991.1.1.2.2.1.1.24',
73      'fdrySnAgentBrdMemoryAvailable'     => '1.3.6.1.4.1.1991.1.1.2.2.1.1.25',
74      );
75
76
77 # Not all interfaces are normally needed to monitor.
78 # You may override the interface filtering in devdiscover-siteconfig.pl:
79 # redefine $Torrus::DevDiscover::Foundry::interfaceFilter
80 # or define $Torrus::DevDiscover::Foundry::interfaceFilterOverlay
81
82 our $interfaceFilter;
83 our $interfaceFilterOverlay;
84 my %fdryInterfaceFilter;
85
86 if( not defined( $interfaceFilter ) )
87 {
88     $interfaceFilter = \%fdryInterfaceFilter;
89 }
90
91 # Key is some unique symbolic name, does not mean anything
92 # ifType is the number to match the interface type
93 # ifDescr is the regexp to match the interface description
94 %fdryInterfaceFilter =
95     (
96      'lb' => {
97          'ifType'  => 24,                    # softwareLoopback
98      },
99      
100      'v' => {
101          'ifType'  => 135,                   # l2vlan
102      },
103
104      'tnl' => {
105          'ifType'  => 150,                   # mplsTunnel
106      },
107      );
108
109
110
111 my %productTypeAttr =
112     (
113      1 => {
114          'desc' => 'BigIron MG8',
115      },
116
117      2 => {
118          'desc' => 'NetIron 40G',
119      },
120
121      3 => {
122          'desc' => 'NetIron IMR 640',
123      },
124      
125      4 => {
126          'desc' => 'NetIron RX 800',
127      },
128      
129      5 => {
130          'desc' => 'NetIron XMR 16000',
131      },
132
133      6 => {
134          'desc' => 'NetIron RX 400',
135      },
136      
137      7 => {
138          'desc' => 'NetIron XMR 8000',
139      },
140
141      8 => {
142          'desc' => 'NetIron RX 200',
143      },
144
145      9 => {
146          'desc' => 'NetIron XMR 4000',
147      },
148      
149      13 => {
150          'desc' => 'NetIron MLX-32',
151      },
152
153      14 => {
154          'desc' => 'NetIron XMR 32000',
155      },
156
157      15 => {
158          'desc' => 'NetIron RX-32',
159      },
160
161      78 => {
162          'desc' => 'FastIron',
163      },
164
165      0 => {
166          'desc' => 'device',
167      },
168      );  
169
170
171 sub checkdevtype
172 {
173     my $dd = shift;
174     my $devdetails = shift;
175     my $retval = 0;
176
177     if( $dd->oidBaseMatch
178         ( 'fdry', $devdetails->snmpVar( $dd->oiddef('sysObjectID') ) ) )
179     {
180         $retval = 1;
181
182         &Torrus::DevDiscover::RFC2863_IF_MIB::addInterfaceFilter
183             ($devdetails, $interfaceFilter);
184
185         if( defined( $interfaceFilterOverlay ) )
186         {
187             &Torrus::DevDiscover::RFC2863_IF_MIB::addInterfaceFilter
188                 ($devdetails, $interfaceFilterOverlay);
189         }
190
191         $devdetails->setCap('interfaceIndexingPersistent');
192
193     }
194     
195     return $retval;
196 }
197
198
199
200 sub discover
201 {
202     my $dd = shift;
203     my $devdetails = shift;
204
205     my $session = $dd->session();
206     my $data = $devdetails->data();
207
208     # NOTE: Comments and Serial number of device
209     
210     my $chassis = $dd->retrieveSnmpOIDs( 'fdrySnChasSerNum',
211                                          'fdrySnChasIdNumber',
212                                          'fdrySnChasArchitectureType',
213                                          'fdrySnChasProductType' );
214     
215     Debug('fdrySnChasSerNum=' . $chassis->{'fdrySnChasSerNum'});
216     Debug('fdrySnChasIdNumber=' . $chassis->{'fdrySnChasIdNumber'});
217     Debug('fdrySnChasArchitectureType=' .
218           $chassis->{'fdrySnChasArchitectureType'});
219     Debug('fdrySnChasProductType=' . $chassis->{'fdrySnChasProductType'});
220     
221     my $productType = 0;
222
223     if( defined( $chassis ) and
224         defined( $productTypeAttr{$chassis->{'fdrySnChasProductType'}} ) )
225     {
226         $productType = $chassis->{'fdrySnChasProductType'};
227     }
228
229     my $deviceComment = 'Brocade ' . $productTypeAttr{$productType}{'desc'};
230         
231     if( defined( $chassis ) )
232     {
233         if( defined( $chassis->{'fdrySnChasSerNum'} ) )
234         {
235             $deviceComment .= ', Chassis S/N: ' .
236                 $chassis->{'fdrySnChasSerNum'};
237         }
238         
239         if( defined( $chassis->{'fdrySnChasIdNumber'} ) and
240             $chassis->{'fdrySnChasIdNumber'} ne '' )
241         {
242             $deviceComment .= ', Chassis ID: ' .
243                 $chassis->{'fdrySnChasIdNumber'};
244         }
245     }
246
247     $data->{'param'}{'comment'} = $deviceComment;
248
249     
250     my $chasTemp = $dd->retrieveSnmpOIDs( 'fdrySnChasActualTemperature',
251                                           'fdrySnChasWarningTemperature',
252                                           'fdrySnChasShutdownTemperature');
253
254     if( defined($chasTemp) and
255         defined($chasTemp->{'fdrySnChasActualTemperature'}) )
256     {
257         $devdetails->setCap('snChasActualTemperature');
258
259         $data->{'fdryChasTemp'}{'warning'} =
260             $chasTemp->{'fdrySnChasWarningTemperature'};
261         $data->{'fdryChasTemp'}{'shutdown'} =
262             $chasTemp->{'fdrySnChasShutdownTemperature'};        
263     }
264        
265     if( $dd->checkSnmpTable('fdrySnAgentBrdTbl') )
266     {
267         $devdetails->setCap('fdryBoardStats'); 
268         $data->{'fdryBoard'} = {};
269
270         # get only the modules with
271         # snAgentBrdModuleStatus = moduleRunning(10)
272         {
273             my $base = $dd->oiddef('fdrySnAgentBrdModuleStatus');
274             my $table = $session->get_table( -baseoid => $base );        
275             my $prefixLen = length( $base ) + 1;
276             
277             while( my( $oid, $status ) = each %{$table} )
278             {
279                 if( $status == 10 )
280                 {
281                     my $brdIndex = substr( $oid, $prefixLen );
282                     $data->{'fdryBoard'}{$brdIndex}{'moduleRunning'} = 1;
283                 }
284             }
285         }
286         
287         # get module descriptions
288         {
289             my $oid = $dd->oiddef('fdrySnAgentBrdMainBrdDescription');
290             my $table = $session->get_table( -baseoid => $oid );        
291             my $prefixLen = length( $oid ) + 1;
292             
293             while( my( $oid, $descr ) = each %{$table} )
294             {
295                 if( length($descr) > 0 )
296                 {
297                     my $brdIndex = substr( $oid, $prefixLen );
298                     
299                     if( $data->{'fdryBoard'}{$brdIndex}{'moduleRunning'} )
300                     {
301                         $data->{'fdryBoard'}{$brdIndex}{'description'} =
302                             $descr;
303                     }
304                 }
305             }
306         }
307
308         # Non-chassis Foundry products set the description to "Invalid Module"
309         if( scalar(keys %{$data->{'fdryBoard'}}) == 1 and
310             $data->{'fdryBoard'}{1}{'moduleRunning'} )
311         {
312             $data->{'fdryBoard'}{1}{'description'} = 'Management';
313         }
314
315         # check if memory statistics are available
316         {
317             my $base = $dd->oiddef('fdrySnAgentBrdMemoryTotal');
318             my $table = $session->get_table( -baseoid => $base );        
319             my $prefixLen = length( $base ) + 1;
320             
321             while( my( $oid, $memory ) = each %{$table} )
322             {
323                 if( $memory > 0 )
324                 {
325                     my $brdIndex = substr( $oid, $prefixLen );
326                     
327                     if( $data->{'fdryBoard'}{$brdIndex}{'moduleRunning'} )
328                     {
329                         $data->{'fdryBoard'}{$brdIndex}{'memory'} = 1;
330                     }
331                 }
332             }
333         }
334
335         # check if CPU stats are available
336         # FOUNDRY-SN-AGENT-MIB::snAgentCpuUtilValue.1.1.1 = Gauge32: 1
337         # FOUNDRY-SN-AGENT-MIB::snAgentCpuUtilValue.1.1.5 = Gauge32: 1
338         # FOUNDRY-SN-AGENT-MIB::snAgentCpuUtilValue.1.1.60 = Gauge32: 1
339         # FOUNDRY-SN-AGENT-MIB::snAgentCpuUtilValue.1.1.300 = Gauge32: 1
340         {
341             my $base = $dd->oiddef('fdrySnAgentCpuUtilValue');
342             my $table = $session->get_table( -baseoid => $base );
343             my $prefixLen = length( $base ) + 1;
344                 
345             while( my( $oid, $val ) = each %{$table} )
346             {
347                 my $brdIndex = substr( $oid, $prefixLen );
348                 $brdIndex =~ s/\.(.+)$//o;
349                 if( $1 eq '1.1' and
350                     $data->{'fdryBoard'}{$brdIndex}{'moduleRunning'} )
351                 {
352                     $data->{'fdryBoard'}{$brdIndex}{'cpu'} = 1;
353                 }
354             }
355         }
356
357         # snAgentCpuUtil100thPercent: supported on NetIron XMR and NetIron
358         # MLX devices running software release 03.9.00 and later, FGS release
359         # 04.3.01 and later, and FSX 04.3.00 and later.
360         # snAgentCpuUtilValue is deprecated in these releases
361         {
362             my $base = $dd->oiddef('fdrySnAgentCpuUtil100thPercent');
363             my $table = $session->get_table( -baseoid => $base );
364             my $prefixLen = length( $base ) + 1;
365                 
366             while( my( $oid, $val ) = each %{$table} )
367             {
368                 my $brdIndex = substr( $oid, $prefixLen );
369                 $brdIndex =~ s/\.(.+)$//o;
370                 if( $1 eq '1.1' and
371                     $data->{'fdryBoard'}{$brdIndex}{'moduleRunning'} )
372                 {
373                     $data->{'fdryBoard'}{$brdIndex}{'cpu-new'} = 1;
374                 }
375             }
376         }        
377         
378         # check if temperature stats are available
379         # exclude the sensors which show zero
380         {
381             my $base = $dd->oiddef('fdrySnAgentTempSensorDescr');
382             my $table = $session->get_table( -baseoid => $base );        
383             my $prefixLen = length( $base ) + 1;
384
385             my $baseVal = $dd->oiddef('fdrySnAgentTempValue');
386             my $values = $session->get_table( -baseoid => $baseVal );
387             
388             while( my( $oid, $descr ) = each %{$table} )
389             {
390                 my $index = substr( $oid, $prefixLen );
391                 my ($brdIndex, $sensor) = split(/\./, $index);
392                 
393                 if( $data->{'fdryBoard'}{$brdIndex}{'moduleRunning'} and
394                     $values->{$baseVal . '.' . $index} > 0 )
395                 {
396                     $data->{'fdryBoard'}{$brdIndex}{'temperature'}{$sensor} =
397                         $descr;
398                     $devdetails->setCap('fdryBoardTemperature'); 
399                 }
400             }
401         }                    
402     }
403     
404     return 1;
405 }
406
407
408 sub buildConfig
409 {
410     my $devdetails = shift;
411     my $cb = shift;
412     my $devNode = shift;
413
414     my $data = $devdetails->data();
415
416     # Chassis Temperature Sensors
417     if( $devdetails->hasCap('snChasActualTemperature') and not
418         $devdetails->hasCap('fdryBoardTemperature') )
419     {
420         my $param = {
421             'fdry-chastemp-warning' => $data->{'fdryChasTemp'}{'warning'}/2,
422             'fdry-chastemp-shutdown' => $data->{'fdryChasTemp'}{'shutdown'}/2,
423         };
424                          
425         my $templates = [ 'Foundry::fdry-chass-temperature' ];
426
427         $cb->addLeaf( $devNode, 'Chassis_Temperature',
428                       $param, $templates );
429     }
430     
431     # Board Stats
432     if( $devdetails->hasCap('fdryBoardStats') )
433     {
434         my $brdNode = $devNode;
435         if( scalar(keys %{$data->{'fdryBoard'}}) > 1 )
436         {
437             my $param = {
438                 'node-display-name' => 'Linecard Statistics',
439                 'comment' => 'CPU, Memory, and Temperature information',
440             };
441             
442             $brdNode =
443                 $cb->addSubtree( $devNode, 'Linecard_Statistics', $param );
444         }
445        
446         $cb->addTemplateApplication( $brdNode,
447                                      'Foundry::fdry-board-overview' );
448         
449             
450         foreach my $brdIndex ( sort {$a <=> $b} keys %{$data->{'fdryBoard'}} )
451         {
452             my $descr = $data->{'fdryBoard'}{$brdIndex}{'description'};
453             my $param = {
454                 'comment'  => $descr,
455                 'fdry-board-index' => $brdIndex,
456                 'fdry-board-descr' => $descr,
457                 'nodeid' => 'module//%nodeid-device%//' . $brdIndex,
458             };
459             
460             my $linecardNode =
461                 $cb->addSubtree( $brdNode, 'Linecard_' . $brdIndex,
462                                  $param,
463                                  [ 'Foundry::fdry-board-subtree' ]);
464             
465             if( $data->{'fdryBoard'}{$brdIndex}{'memory'} )
466             {
467                 $cb->addSubtree( $linecardNode, 'Memory_Statistics', {},
468                                  [ 'Foundry::fdry-board-memstats' ]);
469             }
470             
471
472             my $cpuOid;            
473             if( $data->{'fdryBoard'}{$brdIndex}{'cpu-new'} )
474             {
475                 $cpuOid = '$fdrySnAgentCpuUtil100thPercent';
476             }
477             elsif( $data->{'fdryBoard'}{$brdIndex}{'cpu'} )                
478             {
479                 $cpuOid = '$fdrySnAgentCpuUtilValue';
480             }
481
482             if( defined( $cpuOid ) )
483             {
484                 
485                 $cb->addSubtree
486                     ( $linecardNode, 'CPU_Statistics',
487                       {
488                           'fdry-cpu-base' => $cpuOid,
489                           'nodeid' => 'cpu//%nodeid-device%//' . $brdIndex,
490                       },
491                       [ 'Foundry::fdry-board-cpustats' ]);
492             }
493             
494             if( defined( $data->{'fdryBoard'}{$brdIndex}{'temperature'} ) )
495             {
496                 my $tempNode =
497                     $cb->addSubtree( $linecardNode, 'Temperature_Statistics',
498                                      {}, ['Foundry::fdry-board-tempstats']);
499
500                 # Build a multi-graph for all sensors
501                 
502                 my @colors =
503                     ('##one', '##two', '##three', '##four', '##five',
504                      '##six', '##seven', '##eight', '##nine', '##ten');
505
506                 my $mgParam = {
507                     'comment' => 'Board temperature sensors combined',
508                     'ds-type' => 'rrd-multigraph',
509                     'vertical-label' => 'Degrees Celcius',
510                     'nodeid' => 'temp//%nodeid-device%//' . $brdIndex,
511                 };
512
513                 my @sensors;
514                 
515                 foreach my $sensor
516                     ( sort {$a <=> $b}
517                       keys %{$data->{'fdryBoard'}{$brdIndex}{'temperature'}} )
518                 {
519                     my $leafName = 'sensor_' . $sensor;
520                     
521                     my $descr = $data->{'fdryBoard'}{$brdIndex}{
522                         'temperature'}{$sensor};
523
524                     my $short = 'Temperature sensor ' . $sensor;
525                     
526                     my $param = {
527                         'comment'            => $descr,
528                         'precedence'         => 1000 - $sensor,
529                         'sensor-index'       => $sensor,
530                         'sensor-short'       => $short,
531                         'sensor-description' => $descr,                        
532                     };
533                     
534                     $cb->addLeaf
535                         ( $tempNode, $leafName, $param,
536                           ['Foundry::fdry-board-temp-sensor-halfcelsius'] );
537                     
538                     push(@sensors, $leafName);
539                     
540                     $mgParam->{'ds-expr-' . $leafName} =
541                         '{' . $leafName . '}';
542                     $mgParam->{'graph-legend-' . $leafName} = $short;
543                     $mgParam->{'line-style-' . $leafName} = 'LINE2';
544
545                     my $color = shift @colors;
546                     if( not defined( $color ) )
547                     {
548                         Error('Too many sensors on one Foundry board');
549                         $color = '##black';
550                     }                    
551                     $mgParam->{'line-color-' . $leafName} = $color;
552                     
553                     $mgParam->{'line-order-' . $leafName} = $sensor;
554                 }
555
556                 $mgParam->{'ds-names'} = join(',', @sensors);
557
558                 $cb->addLeaf( $tempNode, 'Temperature_Overview', $mgParam );
559             }
560         }
561     }
562 }
563
564
565
566 1;