1#!@@PERL@@ -w
2# -*- perl -*-
3
4=head1 NAME
5
6snmp__sensors_mbm_volt - Plugin to fetch sensor data from Windows
7boxes running Motherboard Monitor <http://mbm.livewiredev.com/> and
8SNMP-Informant - MBM agent <http://www.snmp-informant.com/>.
9
10=head1 CONFIGURATION
11
12The following environment variables are used by this plugin:
13
14 host      - SNMP host
15 port      - SNMP port
16 community - SNMP community
17
18=head1 AUTHOR
19
20Copyright (C) 2004 Jimmy Olsen
21
22=head1 LICENSE
23
24This program is free software; you can redistribute it and/or
25modify it under the terms of the GNU General Public License
26as published by the Free Software Foundation; version 2 dated June,
271991.
28
29This program is distributed in the hope that it will be useful,
30but WITHOUT ANY WARRANTY; without even the implied warranty of
31MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
32GNU General Public License for more details.
33
34You should have received a copy of the GNU General Public License
35along with this program; if not, write to the Free Software
36Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
37
38=head1 MAGIC MARKERS
39
40 #%# family=snmpauto
41 #%# capabilities=snmpconf
42
43=cut
44
45use strict;
46use Net::SNMP;
47
48my $MAXLABEL = 20;
49
50my $host      = $ENV{host}      || undef;
51my $port      = $ENV{port}      || 161;
52my $community = $ENV{community} || "public";
53my $iface     = $ENV{interface} || undef;
54
55my $response;
56
57if (defined $ARGV[0] and $ARGV[0] eq "snmpconf")
58{
59	print "require 1.3.6.1.4.1.9600.1.10.6.1.1.\n";
60	print "require 1.3.6.1.4.1.9600.1.10.6.1.3. 2\n"; # Type=voltage
61	print "require 1.3.6.1.4.1.9600.1.10.6.1.7. [1-9]\n"; # Low value != 0
62	print "require 1.3.6.1.4.1.9600.1.10.6.1.9. [1-9]\n"; # High value != 0
63
64	exit 0;
65}
66
67if ($0 =~ /^(?:|.*\/)snmp_([^_]+)_sensors_mbm_volt$/)
68{
69	$host  = $1;
70	if ($host =~ /^([^:]+):(\d+)$/)
71	{
72		$host = $1;
73		$port = $2;
74	}
75}
76elsif (!defined($host))
77{
78	print "# Debug: $0 -- $1\n" if $Munin::Plugin::SNMP::DEBUG;
79	die "# Error: couldn't understand what I'm supposed to monitor.";
80}
81
82# The OIDs we're after
83my $mbmDeviceType    = "1.3.6.1.4.1.9600.1.10.6.1.3."; # Should be 2 (volt)
84my $mbmHighWatermark = "1.3.6.1.4.1.9600.1.10.6.1.7."; # Should be non-zero
85my $mbmLowWatermark  = "1.3.6.1.4.1.9600.1.10.6.1.9."; # Should be non-zero
86my $mbmName          = "1.3.6.1.4.1.9600.1.10.6.1.2."; # Name of sensor
87my $mbmValue         = "1.3.6.1.4.1.9600.1.10.6.1.6."; # Data point
88
89my ($session, $error) = Net::SNMP->session(
90		-hostname  => $host,
91		-community => $community,
92		-port      => $port
93	);
94
95if (!defined ($session))
96{
97	die "Croaking: $error";
98}
99
100# First we want to find the harddisks...
101my $correct_type      = get_by_regex ($session, $mbmDeviceType, "^2\$");
102my $correct_high      = get_by_regex ($session, $mbmHighWatermark, "[1-9]");
103my $correct_low       = get_by_regex ($session, $mbmLowWatermark, "[1-9]");
104
105my @keep = ();
106
107foreach my $id (keys %$correct_type)
108{
109	if (exists $correct_high->{$id} and
110	    exists $correct_low->{$id})
111	{
112	    push (@keep, $id);
113	}
114}
115
116my %sensors;
117
118foreach my $kept (@keep) # For each temp sensor...
119{
120    $sensors{$kept}{name} = get_single ($session, $mbmName . "$kept");
121}
122
123if (defined $ARGV[0] and $ARGV[0] eq "config")
124{
125	print "host_name $host\n" unless $host eq 'localhost';
126	print "graph_title Voltages\n";
127	print "graph_vlabel Volt\n";
128	print "graph_category sensors\n";
129	print "graph_info This graph shows voltages in the system.\n";
130
131	foreach my $sensor (sort(keys %sensors))
132	{
133		print (&get_name_by_sensor ($sensors{$sensor}{name}), ".label ");
134		print (length($sensors{$sensor}{name})<=$MAXLABEL ? $sensors{$sensor}{name} : "...".substr($sensors{$sensor}{name},-($MAXLABEL-3)));
135		print ("\n");
136		print (&get_name_by_sensor ($sensors{$sensor}{name}), ".info Voltage readout from the motherboard sensor \"$sensors{$sensor}{name}\".\n");
137	}
138	exit 0;
139}
140
141foreach my $sensor (keys %sensors)
142{
143    my $val = get_single ($session, $mbmValue . $sensor);
144    print (&get_name_by_sensor ($sensors{$sensor}{name}), ".value $val\n");
145}
146
147sub get_single
148{
149	my $handle = shift;
150	my $oid    = shift;
151
152	print "# Getting single \"$oid\"..." if $Munin::Plugin::SNMP::DEBUG;
153
154	$response = $handle->get_request ($oid);
155
156	if (!defined $response->{$oid})
157	{
158	    print "undef\n" if $Munin::Plugin::SNMP::DEBUG;
159	    return undef;
160	}
161	else
162	{
163	    print "\"$response->{$oid}\"\n" if $Munin::Plugin::SNMP::DEBUG;
164	    return $response->{$oid};
165	}
166}
167
168sub get_by_regex
169{
170	my $handle = shift;
171	my $oid    = shift;
172	my $regex  = shift;
173	my $result = {};
174	my $num    = 0;
175	my $ret    = $oid . "0";
176	my $response;
177
178	print "# Starting browse of $oid...\n" if $Munin::Plugin::SNMP::DEBUG;
179
180	while (1)
181	{
182		if ($num == 0)
183		{
184			print "# Checking for $ret...\n" if $Munin::Plugin::SNMP::DEBUG;
185			$response = $handle->get_request ($ret);
186		}
187		if ($num or !defined $response)
188		{
189			print "# Checking for sibling of $ret...\n" if $Munin::Plugin::SNMP::DEBUG;
190			$response = $handle->get_next_request ($ret);
191		}
192		if (!$response)
193		{
194			return undef;
195		}
196		my @keys = keys %$response;
197		$ret = $keys[0];
198		print "# Analyzing $ret (compared to $oid)...\n" if $Munin::Plugin::SNMP::DEBUG;
199		last unless ($ret =~ /^$oid/);
200		$num++;
201		next unless ($response->{$ret} =~ /$regex/);
202		@keys = split (/\./, $ret);
203		$result->{$keys[-1]} = $response->{$ret};;
204		print "# Index $num: ", $keys[-1], " (", $response->{$ret}, ")\n" if $Munin::Plugin::SNMP::DEBUG;
205	};
206	return $result;
207}
208
209sub get_name_by_sensor
210{
211    my $mp = shift;
212    $mp =~ s/[^a-z0-9_]/_/gi;
213    $mp =~ tr/A-Z/a-z/;
214    return "p" . $mp;
215}
216