3 # collectd - snmp-probe-host.px
4 # Copyright (C) 2008 Florian octo Forster
6 # This program is free software; you can redistribute it and/or modify it
7 # under the terms of the GNU General Public License as published by the
8 # Free Software Foundation; only version 2 of the License is applicable.
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # General Public License for more details.
15 # You should have received a copy of the GNU General Public License along
16 # with this program; if not, write to the Free Software Foundation, Inc.,
17 # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 # Florian octo Forster <octo at noris.net>
26 use Config::General ('ParseConfig');
27 use Getopt::Long ('GetOptions');
35 %conf = ParseConfig (-ConfigFile => $file,
37 -UseApacheInclude => 1,
38 -IncludeDirectories => 1,
39 ($Config::General::VERSION >= 2.38) ? (-IncludeAgain => 0) : (),
40 -MergeDuplicateBlocks => 1,
57 if (!$conf->{'table'} || !$conf->{'values'})
59 warn "No 'table' or 'values' setting";
63 @oids = split (/"\s*"/, $conf->{'values'});
64 if ($conf->{'table'} =~ m/^(true|yes|on)$/i)
67 if (defined ($conf->{'instance'}))
69 push (@oids, $conf->{'instance'});
75 #print "probe_one: \@oids = (" . join (', ', @oids) . ");\n";
82 if ($oid_orig =~ m/[^0-9\.]/)
84 my $tmp = SNMP::translateObj ($oid_orig);
87 warn ("Cannot translate OID $oid_orig");
93 $vb = SNMP::Varbind->new ([$oid_orig]);
97 $status = $sess->get ($vb);
98 if ($sess->{'ErrorNum'} != 0)
107 $status = $sess->getnext ($vb);
108 if ($sess->{'ErrorNum'} != 0)
113 $oid_copy = $vb->[0];
114 if ($oid_copy =~ m/[^0-9\.]/)
116 my $tmp = SNMP::translateObj ($oid_copy);
119 warn ("Cannot translate OID $oid_copy");
125 #print "$oid_orig > $oid_copy ?\n";
126 if (substr ($oid_copy, 0, length ($oid_orig)) ne $oid_orig)
132 #print STDOUT Data::Dumper->Dump ([$oid_orig, $status], [qw(oid_orig status)]);
141 my $community = shift;
151 @status = getaddrinfo ($host, 'snmp');
154 my $family = shift (@status);
155 my $socktype = shift (@status);
156 my $proto = shift (@status);
157 my $saddr = shift (@status);
158 my $canonname = shift (@status);
162 ($host, $port) = getnameinfo ($saddr, NI_NUMERICHOST);
169 warn ("getnameinfo failed: $host");
182 $sess = new SNMP::Session (DestHost => $host,
183 Community => $community,
198 if (probe_one ($sess, $data->{$name}))
200 push (@valid_data, $name);
203 if ((@valid_data == 0) && ((time () - $begin) > 10))
217 } # while ($version > 0)
228 Community "$community"
230 for (sort (@valid_data))
232 print " Collect \"$_\"\n";
243 Usage: snmp-probe-host.px --host <host> [options]
246 -H | --host Hostname of the device to probe.
247 -C | --config Path to config file holding the SNMP data blocks.
248 -c | --community SNMP community to use. Default: `public'.
249 -h | --help Print this information and exit.
257 snmp-probe-host.px - Find out what information an SNMP device provides.
261 ./snmp-probe-host.px --host switch01.mycompany.com --community ei2Acoum
265 The C<snmp-probe-host.px> script can be used to automatically generate SNMP
266 configuration snippets for collectd's snmp plugin (see L<collectd-snmp(5)>).
268 This script parses the collectd configuration and detecs all "data" blocks that
269 are defined for the SNMP plugin. It then queries the device specified on the
270 command line for all OIDs and registeres which OIDs could be answered correctly
271 and which resulted in an error. With that information the script figures out
272 which "data" blocks can be used with this hosts and prints an appropriate
273 "host" block to standard output.
275 The script first tries to contact the device via SNMPv2. If after ten seconds
276 no working "data" block has been found, it will try to downgrade to SNMPv1.
277 This is a bit a hack, but works for now.
282 my $file = '/etc/collectd/collectd.conf';
283 my $community = 'public';
289 The following command line options are accepted:
293 =item B<--host> I<hostname>
295 Hostname of the device. This B<should> be a fully qualified domain name (FQDN),
296 but anything the system can resolve to an IP address will word. B<Required
299 =item B<--config> I<config file>
301 Sets the name of the collectd config file which defined the SNMP "data" blocks.
302 Due to limitations of the config parser used in this script
303 (C<Config::General>), C<Include> statements cannot be parsed correctly.
304 Defaults to F</etc/collectd/collectd.conf>.
306 =item B<--community> I<community>
308 SNMP community to use. Should be pretty straight forward.
314 GetOptions ('H|host|hostname=s' => \$host,
315 'C|conf|config=s' => \$file,
316 'c|community=s' => \$community,
317 'h|help' => \&exit_usage) or die;
321 print STDERR "No hostname given. Please use `--host'.\n";
325 $conf = get_config ($file) or die ("Cannot read config");
327 if (!defined ($conf->{'plugin'})
328 || !defined ($conf->{'plugin'}{'snmp'})
329 || !defined ($conf->{'plugin'}{'snmp'}{'data'}))
331 print STDERR "Error: No <plugin>, <snmp>, or <data> block found.\n";
335 probe_all ($host, $community, $conf->{'plugin'}{'snmp'}{'data'});
345 C<Include> statements in the config file are not handled correctly.
349 SNMPv2 / SNMPv1 detection is a hack.
355 Copyright (c) 2008 by Florian octo Forster
356 E<lt>octoE<nbsp>atE<nbsp>noris.netE<gt>. Licensed under the terms of the GPLv2.
357 Written for the norisE<nbsp>networkE<nbsp>AG L<http://noris.net/>.
361 # vim: set sw=2 sts=2 ts=8 et :