File Coverage

lib/Net/SNMP/Poller.pm
Criterion Covered Total %
statement 26 66 39.3
branch 3 28 10.7
condition 1 9 11.1
subroutine 7 10 70.0
pod 3 3 100.0
total 40 116 34.4


line stmt bran cond sub pod time code
1             package Net::SNMP::Poller;
2              
3 1     1   22526 use 5.006;
  1         6  
  1         44  
4 1     1   6 use strict;
  1         3  
  1         34  
5 1     1   5 use warnings;
  1         7  
  1         30  
6 1     1   6 use Carp;
  1         3  
  1         74  
7 1     1   1493 use Net::SNMP;
  1         84444  
  1         787  
8              
9             =head1 NAME
10              
11             Net::SNMP::Poller - Simple poller for non-blocking SNMP queries
12              
13             =head1 VERSION
14              
15             Version 0.05
16              
17             =cut
18              
19             our $VERSION = '0.05';
20              
21              
22             =head1 SYNOPSIS
23              
24             This module takes a hashref of hosts -> session / request info, performs SNMP
25             queries then returns the results.
26              
27             use Net::SNMP::Poller;
28              
29             # so far, logfile is the only supported option
30             my $opts = {
31             logfile => '/tmp/log',
32             };
33              
34             my $obj = Net::SNMP::Poller->new( $opts ); # $opts is optional
35              
36             # data structure is hostname => key-value pairs of SNMP session / request
37             # information. You can specify any options that Net::SNMP::session() and
38             # Net::SNMP::get_request() methods are supporting. This module will perform
39             # overrides appropriately.
40             my $ref = {
41             'localhost' => {
42             version => 1,
43             community => 'public',
44             varbindlist => [ '.1.3.6.1.4.1.2021.11.50.0' ],
45             },
46             };
47              
48             my $data = $obj->run( $ref );
49            
50             # the content of $data would be the following:
51             $data = {
52             'localhost' => {
53             '.1.3.6.1.4.1.2021.11.50.0' => 414695
54             }
55             };
56              
57             =head1 SUBROUTINES/METHODS
58              
59             =head2 new
60              
61             The constructor
62              
63             =cut
64              
65             sub new {
66 1     1 1 246 my ( $class, $opts ) = @_;
67              
68 1 50 33     5 croak "opts passed in but not hashref" if ( $opts && ref( $opts ) ne 'HASH' );
69 1 50       5 $opts = {} unless( $opts );
70            
71 1         3 my $self->{ opts } = $opts;
72 1         2 bless $self, $class;
73 1         7 $self->init();
74 1         3 return $self;
75             }
76              
77             =head2 init
78              
79             Validates args and initializes the object
80              
81             =cut
82              
83             sub init {
84 1     1 1 2 my $self = shift;
85            
86 1         14 $self->{ session } = [ qw|
87             hostname
88             port
89             localaddr
90             localport
91             nonblocking
92             version
93             domain
94             timeout
95             retries
96             maxmsgsize
97             translate
98             debug
99             community
100             username
101             authkey
102             authpassword
103             authprotocol
104             privkey
105             privpassword
106             privprotocol
107             | ];
108              
109 1         4 $self->{ request } = [ qw|
110             callback
111             delay
112             contextengineid
113             contextname
114             varbindlist
115             | ];
116            
117 1 50       4 if ( my $log = $self->{ opts }->{ logfile } ) {
118 0 0         open( my $fh, ">", $log ) or croak "could not open $log: $!\n";
119 0           $self->{ logfh } = $fh;
120             }
121             }
122              
123             =head2 run
124              
125             Performs non-blocking snmp queries and return a data structure
126              
127             =cut
128              
129             sub run {
130 0     0     my ( $self, $ref ) = @_;
131 0 0 0       croak "requires hashref of host data" unless ( $ref && ref( $ref ) eq 'HASH' );
132            
133             my $callback = sub {
134 0     0     $self->callback(@_);
135 0           };
136            
137 0           my $logfh = $self->{ logfh };
138            
139 0           for my $host ( keys %{ $ref } ) {
  0            
140 0           my %session_opts;
141 0           my @session = @{ $self->{ session } };
  0            
142 0           for my $key ( @session ) {
143 0 0         $session_opts{ $key } = $ref->{ $host }->{ $key }
144             if ( defined $ref->{ $host }->{ $key } );
145             }
146            
147 0           my ( $session, $error ) = Net::SNMP->session(
148             hostname => $host,
149             nonblocking => 1,
150             %session_opts,
151             );
152              
153 0 0         if ( !defined $session ) {
154 0           my $string = sprintf "ERROR: Failed to create session for host '%s': %s.\n", $host, $error;
155 0 0         ( $logfh ) ? print $logfh $string : print $string;
156 0           next;
157             }
158            
159 0           my @request = @{ $self->{ request } };
  0            
160 0           my %request_opts;
161 0           for my $key ( @request ) {
162 0 0         $request_opts{ $key } = $ref->{ $host }->{ $key }
163             if ( defined $ref->{ $host }->{ $key } );
164             }
165              
166 0           my $result = $session->get_request(
167             callback => [$callback],
168             %request_opts,
169             );
170              
171 0 0         if ( !defined $result ) {
172 0           my $string = sprintf "ERROR: Failed to queue get request for host '%s': %s.\n",
173             $session->hostname(), $session->error();
174 0 0         ( $logfh ) ? print $logfh $string : print $string;
175             }
176             }
177              
178 0           snmp_dispatcher();
179 0 0 0       close( $logfh ) or croak "could not close log filehandle: $!" if ( $logfh );
180 0           return $self->{ data };
181             }
182              
183             =head2 callback
184              
185             Callback method for Net::SNMP to invoke.
186              
187             =cut
188              
189             sub callback {
190 0     0 1   my ( $self, $session ) = @_;
191            
192 0           my $result = $session->var_bind_list();
193 0           my $host = $session->hostname();
194 0           my $logfh = $self->{ logfh };
195            
196 0 0         if ( !defined $result ) {
197 0           my $string = sprintf "ERROR: Get request failed for host '%s': %s.\n", $host, $session->error();
198 0 0         ( $logfh ) ? print $logfh $string : print $string;
199 0           return;
200             }
201              
202 0           $self->{ data }->{ $host } = $result;
203             }
204              
205             =head1 AUTHOR
206              
207             Satoshi Yagi, C<< >>
208              
209             =head1 BUGS
210              
211             Please report any bugs or feature requests to C, or through
212             the web interface at L. I will be notified, and then you'll
213             automatically be notified of progress on your bug as I make changes.
214              
215              
216              
217              
218             =head1 SUPPORT
219              
220             You can find documentation for this module with the perldoc command.
221              
222             perldoc Net::SNMP::Poller
223              
224              
225             You can also look for information at:
226              
227             =over 4
228              
229             =item * RT: CPAN's request tracker (report bugs here)
230              
231             L
232              
233             =item * AnnoCPAN: Annotated CPAN documentation
234              
235             L
236              
237             =item * CPAN Ratings
238              
239             L
240              
241             =item * Search CPAN
242              
243             L
244              
245             =back
246              
247              
248             =head1 ACKNOWLEDGEMENTS
249              
250              
251             =head1 LICENSE AND COPYRIGHT
252              
253             Copyright 2012-2013 Satoshi Yagi.
254              
255             This program is free software; you can redistribute it and/or modify it
256             under the terms of the the Artistic License (2.0). You may obtain a
257             copy of the full license at:
258              
259             L
260              
261             Any use, modification, and distribution of the Standard or Modified
262             Versions is governed by this Artistic License. By using, modifying or
263             distributing the Package, you accept this license. Do not use, modify,
264             or distribute the Package, if you do not accept this license.
265              
266             If your Modified Version has been derived from a Modified Version made
267             by someone other than you, you are nevertheless required to ensure that
268             your Modified Version complies with the requirements of this license.
269              
270             This license does not grant you the right to use any trademark, service
271             mark, tradename, or logo of the Copyright Holder.
272              
273             This license includes the non-exclusive, worldwide, free-of-charge
274             patent license to make, have made, use, offer to sell, sell, import and
275             otherwise transfer the Package with respect to any patent claims
276             licensable by the Copyright Holder that are necessarily infringed by the
277             Package. If you institute patent litigation (including a cross-claim or
278             counterclaim) against any party alleging that the Package constitutes
279             direct or contributory patent infringement, then this Artistic License
280             to you shall terminate on the date that such litigation is filed.
281              
282             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
283             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
284             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
285             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
286             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
287             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
288             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
289             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
290              
291              
292             =cut
293              
294             1; # End of Net::SNMP::Poller