3 # collectd - snmp-probe-host.px
4 # Copyright (C) 2008,2009 Florian octo Forster
5 # Copyright (C) 2009 noris network AG
7 # This program is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by the
9 # Free Software Foundation; only version 2 of the License is applicable.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License along
17 # with this program; if not, write to the Free Software Foundation, Inc.,
18 # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 # Florian octo Forster <octo at noris.net>
27 use Config::General ('ParseConfig');
28 use Getopt::Long ('GetOptions');
33 'IF-MIB64' => qr/^\.?1\.3\.6\.1\.2\.1\.31/,
34 'IF-MIB32' => qr/^\.?1\.3\.6\.1\.2\.1\.2/
42 %conf = ParseConfig (-ConfigFile => $file,
44 -UseApacheInclude => 1,
45 -IncludeDirectories => 1,
46 ($Config::General::VERSION >= 2.38) ? (-IncludeAgain => 0) : (),
47 -MergeDuplicateBlocks => 1,
60 my $excludes = @_ ? shift : [];
65 if (!$conf->{'table'} || !$conf->{'values'})
67 warn "No 'table' or 'values' setting";
71 @oids = split (/"\s*"/, $conf->{'values'});
72 if ($conf->{'table'} =~ m/^(true|yes|on)$/i)
75 if (defined ($conf->{'instance'}))
77 push (@oids, $conf->{'instance'});
83 #print "probe_one: \@oids = (" . join (', ', @oids) . ");\n";
90 if ($oid_orig =~ m/[^0-9\.]/)
92 my $tmp = SNMP::translateObj ($oid_orig);
95 warn ("Cannot translate OID $oid_orig");
109 $vb = SNMP::Varbind->new ([$oid_orig]);
113 $status = $sess->get ($vb);
114 if ($sess->{'ErrorNum'} != 0)
118 if (!defined ($status))
122 if ("$status" eq 'NOSUCHOBJECT')
131 $status = $sess->getnext ($vb);
132 if ($sess->{'ErrorNum'} != 0)
137 $oid_copy = $vb->[0];
138 if ($oid_copy =~ m/[^0-9\.]/)
140 my $tmp = SNMP::translateObj ($oid_copy);
143 warn ("Cannot translate OID $oid_copy");
149 #print "$oid_orig > $oid_copy ?\n";
150 if (substr ($oid_copy, 0, length ($oid_orig)) ne $oid_orig)
156 #print STDOUT Data::Dumper->Dump ([$oid_orig, $status], [qw(oid_orig status)]);
165 my $community = shift;
167 my $excludes = @_ ? shift : [];
176 @status = getaddrinfo ($host, 'snmp');
179 my $family = shift (@status);
180 my $socktype = shift (@status);
181 my $proto = shift (@status);
182 my $saddr = shift (@status);
183 my $canonname = shift (@status);
187 ($host, $port) = getnameinfo ($saddr, NI_NUMERICHOST);
194 warn ("getnameinfo failed: $host");
207 $sess = new SNMP::Session (DestHost => $host,
208 Community => $community,
223 if (probe_one ($sess, $data->{$name}, $excludes))
225 push (@valid_data, $name);
228 if ((@valid_data == 0) && ((time () - $begin) > 10))
242 } # while ($version > 0)
248 Community "$community"
250 for (sort (@valid_data))
252 print " Collect \"$_\"\n";
257 # WARNING: Autoconfiguration failed.
258 # TODO: Add one or more `Collect' statements here:
271 Usage: snmp-probe-host.px --host <host> [options]
274 -H | --host Hostname of the device to probe.
275 -C | --config Path to config file holding the SNMP data blocks.
276 -c | --community SNMP community to use. Default: `public'.
277 -h | --help Print this information and exit.
278 -x | --exclude Exclude a specific MIB. Call with "help" for more
285 sub exit_usage_exclude
287 print "Available exclude MIBs:\n\n";
288 for (sort (keys %ExcludeOptions))
298 snmp-probe-host.px - Find out what information an SNMP device provides.
302 ./snmp-probe-host.px --host switch01.mycompany.com --community ei2Acoum
306 The C<snmp-probe-host.px> script can be used to automatically generate SNMP
307 configuration snippets for collectd's snmp plugin (see L<collectd-snmp(5)>).
309 This script parses the collectd configuration and detecs all "data" blocks that
310 are defined for the SNMP plugin. It then queries the device specified on the
311 command line for all OIDs and registeres which OIDs could be answered correctly
312 and which resulted in an error. With that information the script figures out
313 which "data" blocks can be used with this hosts and prints an appropriate
314 "host" block to standard output.
316 The script first tries to contact the device via SNMPv2. If after ten seconds
317 no working "data" block has been found, it will try to downgrade to SNMPv1.
318 This is a bit a hack, but works for now.
323 my $file = '/etc/collectd/collectd.conf';
324 my $community = 'public';
331 The following command line options are accepted:
335 =item B<--host> I<hostname>
337 Hostname of the device. This B<should> be a fully qualified domain name (FQDN),
338 but anything the system can resolve to an IP address will word. B<Required
341 =item B<--config> I<config file>
343 Sets the name of the collectd config file which defined the SNMP "data" blocks.
344 Due to limitations of the config parser used in this script
345 (C<Config::General>), C<Include> statements cannot be parsed correctly.
346 Defaults to F</etc/collectd/collectd.conf>.
348 =item B<--community> I<community>
350 SNMP community to use. Should be pretty straight forward.
352 =item B<--exclude> I<MIB>
354 This option can be used to exclude specific data from being enabled in the
355 generated config. Currently the following MIBs are understood:
361 Exclude interface information, such as I<ifOctets> and I<ifPackets>.
369 GetOptions ('H|host|hostname=s' => \$host,
370 'C|conf|config=s' => \$file,
371 'c|community=s' => \$community,
372 'x|exclude=s' => \@excludes,
373 'h|help' => \&exit_usage) or die;
377 print STDERR "No hostname given. Please use `--host'.\n";
383 my $tmp = join (',', @excludes);
384 my @tmp = split (/\s*,\s*/, $tmp);
392 exit_usage_exclude ();
394 elsif (!exists ($ExcludeOptions{$mib}))
396 print STDERR "No such MIB: $mib\n";
397 exit_usage_exclude ();
399 push (@excludes, $ExcludeOptions{$mib});
403 $conf = get_config ($file) or die ("Cannot read config");
405 if (!defined ($conf->{'plugin'})
406 || !defined ($conf->{'plugin'}{'snmp'})
407 || !defined ($conf->{'plugin'}{'snmp'}{'data'}))
409 print STDERR "Error: No <plugin>, <snmp>, or <data> block found.\n";
413 probe_all ($host, $community, $conf->{'plugin'}{'snmp'}{'data'}, \@excludes);
423 C<Include> statements in the config file are not handled correctly.
427 SNMPv2 / SNMPv1 detection is a hack.
433 Copyright (c) 2008 by Florian octo Forster
434 E<lt>octoE<nbsp>atE<nbsp>noris.netE<gt>. Licensed under the terms of the GPLv2.
435 Written for the norisE<nbsp>networkE<nbsp>AG L<http://noris.net/>.
439 # vim: set sw=2 sts=2 ts=8 et :