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) && ($conf->{'instance'}))
67 push (@oids, $conf->{'instance'});
72 #print "probe_one: \@oids = (" . join (', ', @oids) . ");\n";
79 if ($oid_orig =~ m/[^0-9\.]/)
81 my $tmp = SNMP::translateObj ($oid_orig);
84 warn ("Cannot translate OID $oid_orig");
90 $vb = SNMP::Varbind->new ([$oid_orig]);
94 $status = $sess->get ($vb);
95 if ($sess->{'ErrorNum'} != 0)
104 $status = $sess->getnext ($vb);
105 if ($sess->{'ErrorNum'} != 0)
110 $oid_copy = $vb->[0];
111 if ($oid_copy =~ m/[^0-9\.]/)
113 my $tmp = SNMP::translateObj ($oid_copy);
116 warn ("Cannot translate OID $oid_copy");
122 #print "$oid_orig > $oid_copy ?\n";
123 if (substr ($oid_copy, 0, length ($oid_orig)) ne $oid_orig)
129 #print STDOUT Data::Dumper->Dump ([$oid_orig, $status], [qw(oid_orig status)]);
138 my $community = shift;
148 @status = getaddrinfo ($host, 'snmp');
151 my $family = shift (@status);
152 my $socktype = shift (@status);
153 my $proto = shift (@status);
154 my $saddr = shift (@status);
155 my $canonname = shift (@status);
159 ($host, $port) = getnameinfo ($saddr, NI_NUMERICHOST);
166 warn ("getnameinfo failed: $host");
179 $sess = new SNMP::Session (DestHost => $host,
180 Community => $community,
195 if (probe_one ($sess, $data->{$name}))
197 push (@valid_data, $name);
200 if ((@valid_data == 0) && ((time () - $begin) > 10))
214 } # while ($version > 0)
225 Community "$community"
227 for (sort (@valid_data))
229 print " Collect \"$_\"\n";
240 Usage: snmp-probe-host.px --host <host> [options]
243 -H | --host Hostname of the device to probe.
244 -C | --config Path to config file holding the SNMP data blocks.
245 -c | --community SNMP community to use. Default: `public'.
246 -h | --help Print this information and exit.
254 snmp-probe-host.px - Find out what information an SNMP device provides.
258 ./snmp-probe-host.px --host switch01.mycompany.com --community ei2Acoum
262 The C<snmp-probe-host.px> script can be used to automatically generate SNMP
263 configuration snippets for collectd's snmp plugin (see L<collectd-snmp(5)>).
265 This script parses the collectd configuration and detecs all "data" blocks that
266 are defined for the SNMP plugin. It then queries the device specified on the
267 command line for all OIDs and registeres which OIDs could be answered correctly
268 and which resulted in an error. With that information the script figures out
269 which "data" blocks can be used with this hosts and prints an appropriate
270 "host" block to standard output.
272 The script first tries to contact the device via SNMPv2. If after ten seconds
273 no working "data" block has been found, it will try to downgrade to SNMPv1.
274 This is a bit a hack, but works for now.
279 my $file = '/etc/collectd/collectd.conf';
280 my $community = 'public';
286 The following command line options are accepted:
290 =item B<--host> I<hostname>
292 Hostname of the device. This B<should> be a fully qualified domain name (FQDN),
293 but anything the system can resolve to an IP address will word. B<Required
296 =item B<--config> I<config file>
298 Sets the name of the collectd config file which defined the SNMP "data" blocks.
299 Due to limitations of the config parser used in this script
300 (C<Config::General>), C<Include> statements cannot be parsed correctly.
301 Defaults to F</etc/collectd/collectd.conf>.
303 =item B<--community> I<community>
305 SNMP community to use. Should be pretty straight forward.
311 GetOptions ('H|host|hostname=s' => \$host,
312 'C|conf|config=s' => \$file,
313 'c|community=s' => \$community,
314 'h|help' => \&exit_usage) or die;
318 print STDERR "No hostname given. Please use `--host'.\n";
322 $conf = get_config ($file) or die ("Cannot read config");
324 if (!defined ($conf->{'plugin'})
325 || !defined ($conf->{'plugin'}{'snmp'})
326 || !defined ($conf->{'plugin'}{'snmp'}{'data'}))
328 print STDERR "Error: No <plugin>, <snmp>, or <data> block found.\n";
332 probe_all ($host, $community, $conf->{'plugin'}{'snmp'}{'data'});
342 C<Include> statements in the config file are not handled correctly.
346 SNMPv2 / SNMPv1 detection is a hack.
352 Copyright (c) 2008 by Florian octo Forster
353 E<lt>octoE<nbsp>atE<nbsp>noris.netE<gt>. Licensed under the terms of the GPLv2.
354 Written for the norisE<nbsp>networkE<nbsp>AG L<http://noris.net/>.
358 # vim: set sw=2 sts=2 ts=8 et :