backport some fixes for "Using a hash as a reference is deprecated" warnings from...
[freeside.git] / torrus / perllib / Torrus / DevDiscover / F5BigIp.pm
1 #  Copyright (C) 2003  Shawn Ferry
2 #
3 #  This program is free software; you can redistribute it and/or modify
4 #  it under the terms of the GNU General Public License as published by
5 #  the Free Software Foundation; either version 2 of the License, or
6 #  (at your option) any later version.
7 #
8 #  This program is distributed in the hope that it will be useful,
9 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 #  GNU General Public License for more details.
12 #
13 #  You should have received a copy of the GNU General Public License
14 #  along with this program; if not, write to the Free Software
15 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
16
17 # $Id: F5BigIp.pm,v 1.1.1.1.2.1 2011-12-16 22:43:56 ivan Exp $
18 # Shawn Ferry <sferry at sevenspace dot com> <lalartu at obscure dot org>
19
20 # F5 BigIp Load Balancer
21
22 package Torrus::DevDiscover::F5BigIp;
23
24 use strict;
25 use Torrus::Log;
26
27
28 $Torrus::DevDiscover::registry{'F5BigIp'} = {
29     'sequence'     => 500,
30     'checkdevtype' => \&checkdevtype,
31     'discover'     => \&discover,
32     'buildConfig'  => \&buildConfig
33     };
34
35 our %oiddef =
36     (
37      # F5
38      'f5'                           => '1.3.6.1.4.1.3375',
39
40      '4.x_globalStatUptime'         => '1.3.6.1.4.1.3375.1.1.1.2.1.0',
41      '3.x_uptime'                   => '1.3.6.1.4.1.3375.1.1.50.0',
42
43      '4.x_globalAttrProductCode'    => '1.3.6.1.4.1.3375.1.1.1.1.5.0',
44
45      '4.x_virtualServer'            => '1.3.6.1.4.1.3375.1.1.3',
46      '4.x_virtualServerNumber'      => '1.3.6.1.4.1.3375.1.1.3.1.0',
47      '4.x_virtualServerTable'       => '1.3.6.1.4.1.3375.1.1.3.2',
48      '4.x_virtualServerIp'          => '1.3.6.1.4.1.3375.1.1.3.2.1.1',
49      '4.x_virtualServerPort'        => '1.3.6.1.4.1.3375.1.1.3.2.1.2',
50      '4.x_virtualServerPool'        => '1.3.6.1.4.1.3375.1.1.3.2.1.30',
51
52      '4.x_poolTable'                => '1.3.6.1.4.1.3375.1.1.7.2',
53      '4.x_poolName'                 => '1.3.6.1.4.1.3375.1.1.7.2.1.1',
54
55      '4.x_poolMemberTable'          => '1.3.6.1.4.1.3375.1.1.8.2',
56      '4.x_poolMemberPoolName'       => '1.3.6.1.4.1.3375.1.1.8.2.1.1',
57      '4.x_poolMemberIpAddress'      => '1.3.6.1.4.1.3375.1.1.8.2.1.2',
58      '4.x_poolMemberPort'           => '1.3.6.1.4.1.3375.1.1.8.2.1.3',
59
60      '4.x_sslProxyTable'            => '1.3.6.1.4.1.3375.1.1.9.2.1',
61      '4.x_sslProxyOrigIpAddress'    => '1.3.6.1.4.1.3375.1.1.9.2.1.1',
62      '4.x_sslProxyOrigPort'         => '1.3.6.1.4.1.3375.1.1.9.2.1.2',
63      '4.x_sslProxyDestIpAddress'    => '1.3.6.1.4.1.3375.1.1.9.2.1.3',
64      '4.x_sslProxyDestPort'         => '1.3.6.1.4.1.3375.1.1.9.2.1.4',
65      '4.x_sslProxyConnLimit'        => '1.3.6.1.4.1.3375.1.1.9.2.1.23',
66
67      );
68
69 # from https://secure.f5.com/validate/help.jsp
70 #HA (BIG-IP high availability software)
71 #3DNS (3-DNS software)
72 #LC (BIG-IP Link Controller software)
73 #LB (BIG-IP Load Balancer 520)
74 #FLB (BIG-IP FireGuard 520)
75 #CLB (BIG-IP Cache Load Balancer 520)
76 #SSL (BIG-IP eCommerce Load Balancer 520)
77 #XLB (BIG-IP user-defined special purpose product for 520 platforms)
78 #ISMAN (iControl Services Manager)
79
80 our %f5_product = (
81     '1'     => { 'product' => 'indeterminate',  'supported' => 0, },
82     '2'     => { 'product' => 'ha',             'supported' => 1, },
83     '3'     => { 'product' => 'lb',             'supported' => 1, },
84     '4'     => { 'product' => 'threedns',       'supported' => 0, },
85     '5'     => { 'product' => 'flb',            'supported' => 0, },
86     '6'     => { 'product' => 'clb',            'supported' => 0, },
87     '7'     => { 'product' => 'xlb',            'supported' => 0, },
88     '8'     => { 'product' => 'ssl',            'supported' => 1, },
89     '10'    => { 'product' => 'test',           'supported' => 0, },
90     '99'    => { 'product' => 'unsupported',    'supported' => 0, },
91     );
92
93 our %f5_sslGatewayLevel = (
94     '1'     => 'none',
95     '3'     => 'tps200',
96     '4'     => 'tps400',
97     '5'     => 'tps600',
98     '6'     => 'tps800',
99     '7'     => 'tps1000',
100     '9'     => 'tps500',
101     '10'    => 'tps1500',
102     '11'    => 'tps2000',
103     '99'    => 'unsupported',
104     );
105
106
107
108
109 sub checkdevtype
110 {
111     my $dd = shift;
112     my $devdetails = shift;
113     my $data = $devdetails->data();
114
115     # You would think globalAttrProductCode would work well
116     # I need more examples to see if ha(2) is specific to
117     # BipIP HA or any ha f5 product
118
119     if( not $dd->checkSnmpTable( 'f5' ) )
120     {
121         return 0;
122     }
123
124     return 1;
125 }
126
127
128 sub discover
129 {
130     my $dd = shift;
131     my $devdetails = shift;
132
133     my $session = $dd->session();
134     my $data = $devdetails->data();
135
136     # SNMP on F5 boxes will become unresponsive over time with large
137     # enough oids-per-pdu values.  10 appears to work for everything however
138     # no exhaustive testing has been done to determine if a higer number
139     # could be used.
140     if( not defined( $data->{'param'}{'snmp-oids-per-pdu'} ) )
141     {
142         my $oidsPerPDU = $devdetails->param('F5BigIp::snmp-oids-per-pdu');
143         if( $oidsPerPDU == 0 )
144         {
145             $oidsPerPDU = 10;
146         }
147         $data->{'param'}{'snmp-oids-per-pdu'} = $oidsPerPDU;
148     }
149
150     # this is rather basic, per-capability checking
151     # may be required in the future
152
153     if( $dd->checkSnmpOID('4.x_globalStatUptime') )
154     {
155         $devdetails->setCap('BigIp_4.x');
156     }
157     elsif( $dd->checkSnmpOID('3.x_uptime') )
158     {
159         # for v3.x we are not supporting detailed stats, so don't check
160         # anything else
161         $devdetails->setCap('BigIp_3.x');
162         return 1;
163     }
164
165     my $product_name;
166     my $product_name;
167     my $result = $dd->retrieveSnmpOIDs( '4.x_globalAttrProductCode' );
168     my $product_code = $result->{'4.x_globalAttrProductCode'};
169
170     $product_name = $f5_product{$product_code}->{'product'};
171     if( $f5_product{$product_code}->{'supported'} )
172     {
173         $devdetails->setCap( 'BigIp_' . $product_name );
174     }
175     else
176     {
177         if( defined($product_name) )
178         {
179             Debug("Found an unsupported F5 product '$product_name'");
180         }
181         else
182         {
183             Debug("Found an unknown F5 product");
184         }
185         return 0;
186     }
187
188     my $poolTable = $session->get_table( -baseoid =>
189                                  $dd->oiddef('4.x_poolTable') );
190
191     if( defined( $poolTable ) )
192     {
193         $devdetails->storeSnmpVars( $poolTable );
194         $devdetails->setCap('BigIp_4.x_PoolTable');
195
196         my $ref = {};
197         $ref->{'indices'} = [];
198         $data->{'poolTable'} = $ref;
199
200         foreach my $INDEX ( $devdetails->
201                             getSnmpIndices( $dd->oiddef('4.x_poolName') ) )
202         {
203             push( @{$ref->{'indices'}}, $INDEX );
204             my $pool = $devdetails->snmpVar($dd->oiddef('4.x_poolName') .
205                                             '.' . $INDEX );
206
207             my $nick = $pool;
208             $nick =~ s/\W/_/g;
209             $nick =~ s/_+/_/g;
210
211             my $param = {};
212             $ref->{$INDEX}->{'param'} = $param;
213             $param->{'nick'} = $nick;
214             $param->{'pool'} = $pool;
215             $param->{'descr'} = "Stats for Pool $pool";
216             $param->{'INDEX'} = $INDEX;
217         }
218
219     }
220
221     my $poolMemberTable =
222         $session->get_table( -baseoid =>
223                              $dd->oiddef('4.x_poolMemberTable') );
224
225     if( defined( $poolMemberTable ) )
226     {
227         $devdetails->storeSnmpVars( $poolMemberTable );
228         $devdetails->setCap('BigIp_4.x_PoolMemberTable');
229
230         my $ref = {};
231         $data->{'poolMemberTable'} = $ref;
232
233         foreach my $INDEX
234             ( $devdetails->
235               getSnmpIndices( $dd->oiddef('4.x_poolMemberPoolName') ) )
236         {
237             push( @{ $ref->{'indices'} }, $INDEX );
238             my $pool =
239                 $devdetails->snmpVar($dd->oiddef('4.x_poolMemberPoolName') .
240                                      '.' . $INDEX );
241             my $ip =
242                 $devdetails->snmpVar($dd->oiddef('4.x_poolMemberIpAddress') .
243                                      '.' . $INDEX );
244             my $port =
245                 $devdetails->snmpVar($dd->oiddef('4.x_poolMemberPort') .
246                                      '.' . $INDEX );
247
248             my $nick = "MEMBER_${pool}_${ip}_${port}";
249             $nick =~ s/\W/_/g;
250             $nick =~ s/_+/_/g;
251
252             my $param = {};
253             $ref->{$INDEX}->{'param'} = $param;
254             $param->{'nick'} = $nick;
255             $param->{'pool'} = $pool;
256             $param->{'descr'} = "Member of Pool $pool IP: $ip Port: $port";
257             $param->{'INDEX'} = $INDEX;
258         }
259
260     }
261
262     my $virtServerNumber = $dd->retrieveSnmpOIDs( '4.x_virtualServerNumber' );
263     if( $virtServerNumber->{'4.x_virtualServerNumber'} > 0 )
264     {
265         my $virtServer = $session->get_table( -baseoid =>
266                                           $dd->oiddef('4.x_virtualServer') );
267         if( defined( $virtServer ) )
268         {
269             $devdetails->storeSnmpVars( $virtServer );
270             $devdetails->setCap('BigIp_4.x_VirtualServer');
271
272             my $ref = {};
273             $data->{'virtualServer'} = $ref;
274
275             foreach my $INDEX
276                 ( $devdetails->
277                   getSnmpIndices( $dd->oiddef('4.x_virtualServerIp') ) )
278             {
279                 push( @{ $ref->{'indices'} }, $INDEX);
280                 my $pool = $devdetails->snmpVar(
281                                 $dd->oiddef('4.x_virtualServerPool') .
282                                 '.' . $INDEX );
283                 my $ip = $devdetails->snmpVar(
284                                 $dd->oiddef('4.x_virtualServerIp') .
285                                 '.' . $INDEX );
286                 my $port = $devdetails->snmpVar(
287                                 $dd->oiddef('4.x_virtualServerPort') .
288                                 '.' . $INDEX );
289
290                 my $param = {};
291                 $ref->{$INDEX}->{'param'} = $param;
292
293                 my $descr = "Virtual Server Pool: $pool IP: $ip Port: $port";
294                 my $nick = "VIP_${pool}_${ip}_${port}";
295                 $nick =~ s/\W/_/g;
296                 $nick =~ s/_+/_/g;
297
298                 $param->{'INDEX'} = $INDEX;
299                 $param->{'descr'} = $descr;
300                 $param->{'nick'} = $nick;
301                 $param->{'pool'} = $pool;
302             }
303         }
304         else
305         {
306             Debug("Virtual Servers Defined but not able to be configured");
307         }
308     }
309
310     my $sslProxyTable = $session->get_table( -baseoid =>
311                             $dd->oiddef('4.x_sslProxyTable') );
312
313     if( defined( $sslProxyTable ) )
314     {
315         $devdetails->storeSnmpVars( $sslProxyTable );
316         $devdetails->setCap('BigIp_4.x_sslProxyTable');
317
318         my $ref = {};
319         $ref->{'indices'} = [];
320         $data->{'sslProxyTable'} = $ref;
321
322         foreach my $INDEX ( $devdetails->
323             getSnmpIndices( $dd->oiddef('4.x_sslProxyOrigIpAddress') ) )
324         {
325             push( @{$ref->{'indices'}}, $INDEX );
326
327             my $origIp = $devdetails->snmpVar(
328                     $dd->oiddef('4.x_sslProxyOrigIpAddress')
329                     . '.' .  $INDEX );
330
331             my $origPort = $devdetails->snmpVar(
332                     $dd->oiddef('4.x_sslProxyOrigPort')
333                     . '.' .  $INDEX );
334
335             my $destIp = $devdetails->snmpVar(
336                     $dd->oiddef('4.x_sslProxyDestIpAddress')
337                     . '.' .  $INDEX );
338
339             my $destPort = $devdetails->snmpVar(
340                     $dd->oiddef('4.x_sslProxyDestPort')
341                     . '.' .  $INDEX );
342
343             my $connLimit = $devdetails->snmpVar(
344                     $dd->oiddef('4.x_sslProxyConnLimit')
345                     . '.' .  $INDEX );
346
347
348
349             my $nick = $origIp . '_' . $origPort . '_' . $destIp .
350                     '_' . $destPort;
351
352             my $param = {};
353             $ref->{$INDEX}->{'param'} = $param;
354             $param->{'nick'} = $nick;
355             $param->{'descr'} = "Stats for SSL Proxy Address: " .
356                     "${origIp}:${origPort} -> ${destIp}:${destPort}";
357             $param->{'INDEX'} = $INDEX;
358             $param->{'connLimit'} = $connLimit;
359
360         }
361
362
363     }
364
365     return 1;
366 }
367
368
369 sub buildConfig
370 {
371     my $devdetails = shift;
372     my $cb = shift;
373     my $devNode = shift;
374     my $data = $devdetails->data();
375
376
377     my $bigIpName = 'BigIp_Global_Stats';
378
379     my $bigIpParam = {
380         'precedence'         => '-100',
381         'comment'            => 'BigIp Global Stats',
382         'rrd-create-dstype'  => 'GAUGE', };
383
384     if( $devdetails->hasCap('BigIp_4.x') )
385     {
386         my $bigIpStatsNode = $cb->addSubtree( $devNode, $bigIpName,
387                 $bigIpParam, [ 'F5BigIp::BigIp_4.x' ]);
388
389         if( $devdetails->hasCap('BigIp_ssl') )
390         {
391             $cb->addTemplateApplication
392                 ( $bigIpStatsNode , 'F5BigIp::BigIp_4.x_sslProxy_Global' );
393         }
394     }
395     elsif( $devdetails->hasCap('BigIp_3.x') )
396     {
397         $cb->addSubtree( $devNode, $bigIpName, $bigIpParam,
398                          [ 'F5BigIp::BigIp_3.x' ]);
399     }
400
401     my $virtName = 'BigIp_VirtualServers';
402
403     my $virtParam = {
404         'precedence'        => '-200',
405         'comment'           => 'Virtual Server(VIP) Stats',
406     };
407
408     my $virtTree;
409
410     if( $devdetails->hasCap('BigIp_4.x_VirtualServer') )
411     {
412         my @templates =
413             ( 'F5BigIp::BigIp_4.x_virtualServer-actvconn-overview' );
414         #    'F5BigIp::BigIp_4.x_virtualServer-connrate-overview');
415
416         $virtTree =
417             $cb->addSubtree( $devNode, $virtName, $virtParam, \@templates );
418
419         my $ref = $data->{'virtualServer'};
420
421         foreach my $INDEX ( @{ $ref->{'indices'} } )
422         {
423             my $server = $ref->{$INDEX}->{'param'};
424
425             $server->{'precedence'} = '-100';
426
427             $cb->addSubtree( $virtTree, $server->{'nick'}, $server,
428                           [ 'F5BigIp::BigIp_4.x_virtualServer' ] );
429         }
430     }
431
432     my $poolName = 'BigIp_Pools';
433     my $poolParam = {
434         'precedence'        => '-300',
435         'comment'           => 'Pool Stats',
436     };
437
438     my $poolTree;
439
440     if( $devdetails->hasCap('BigIp_4.x_PoolTable') )
441     {
442         $poolTree =
443             $cb->addSubtree( $devNode, $poolName, $poolParam,
444                              ['F5BigIp::BigIp_4.x_pool-actvconn-overview']);
445         my $ref = $data->{'poolTable'};
446
447         foreach my $INDEX ( @{ $ref->{'indices'} } )
448         {
449             my $pool = $ref->{$INDEX}->{'param'};
450
451             $pool->{'precedence'} = '-100';
452
453             $cb->addSubtree( $poolTree, $pool->{'pool'}, $pool,
454                           [ 'F5BigIp::BigIp_4.x_pool' ] );
455         }
456
457     }
458
459     my $poolMemberName = 'BigIp_Pool_Members';
460
461     my $poolMemberParam = {
462         'precedence'        => '-400',
463         'comment'           => 'Pool Member Stats',
464     };
465
466     my $poolMemberTree;
467
468     if( $devdetails->hasCap('BigIp_4.x_PoolMemberTable') )
469     {
470         $poolMemberTree =
471             $cb->addSubtree( $devNode, $poolMemberName, $poolMemberParam );
472         my $ref = $data->{'poolMemberTable'};
473
474         foreach my $INDEX ( @{ $ref->{'indices'} } )
475         {
476             my $poolMemberPoolTree;
477             my $lastPoolTree;
478             my $server = $ref->{$INDEX}->{'param'};
479
480             my $poolMemberPoolName = $server->{'pool'};
481             my $poolMemberPoolParam = {
482                 'precidence'    => '-100',
483                 'comment'       => "Members of the $server->{'pool'} Pool",
484             };
485
486
487             if( not defined( $lastPoolTree ) or
488                 $poolMemberPoolName !~ /\b$lastPoolTree\b/ )
489             {
490                 my @templates =
491                     ( 'F5BigIp::BigIp_4.x_poolMember-actvconn-overview' );
492                 $poolMemberPoolTree =
493                     $cb->addSubtree( $poolMemberTree, $poolMemberPoolName,
494                                      $poolMemberPoolParam, \@templates );
495
496                 $lastPoolTree = $poolMemberPoolName;
497
498                 $server->{'precedence'} = '-100';
499
500                 $cb->addSubtree( $poolMemberPoolTree, $server->{'nick'}, $server,
501                               [ 'F5BigIp::BigIp_4.x_poolMember' ] );
502             }
503         }
504     }
505
506
507     # BigIP SSL Product Support
508     if( $devdetails->hasCap('BigIp_4.x_sslProxyTable') )
509     {
510
511         my $bigIpSSLProxies = 'BigIp_SSL_Proxies';
512
513         my $bigIpSSLParam = {
514             'comment'            => 'BigIp SSL Proxies',
515             'rrd-create-dstype'  => 'COUNTER', };
516
517         my $sslProxyTree = $cb->addSubtree(
518                     $devNode, $bigIpSSLProxies, $bigIpSSLParam,
519                     [ 'F5BigIp::BigIp_4.x_sslProxy-currconn-overview' ]);
520
521         my $ref = $data->{'sslProxyTable'};
522
523         foreach my $INDEX ( @{ $ref->{'indices'} } )
524         {
525             my $proxy = $ref->{$INDEX}->{'param'};
526
527             $cb->addSubtree( $sslProxyTree, $proxy->{'nick'}, $proxy,
528                     [ 'F5BigIp::BigIp_4.x_sslProxy' ] );
529         }
530
531     }
532
533 }
534
535
536 1;
537
538
539 # Local Variables:
540 # mode: perl
541 # indent-tabs-mode: nil
542 # perl-indent-level: 4
543 # End: