Projet

Général

Profil

Paste
Télécharger au format
Statistiques
| Branche: | Révision:

root / plugins / sensors / nutups2_ @ ea6afd78

Historique | Voir | Annoter | Télécharger (7,7 ko)

1 9a168e78 Gabor Gombas
#! /usr/bin/perl -w
2
3
=head1 NAME
4
5
nutups2_ - Plugin to monitor UPSes managed by NUT
6
7
=head1 CONFIGURATION
8
9
Generally none needed.
10
11
If you have installed NUT at a non-standard location, then you can specify its
12
location like:
13
14
  [nutups2_*]
15
    env.upsc /some/location/bin/upsc
16
17
=head1 WARNING AND CRITICAL SETTINGS
18
19
If upsc reports 'high' and 'low' values for some attribute, those will used
20
as the critical range. Otherwise the following environment variables can be
21
used to set the defaults for all fields:
22
23
    env.warning
24
    env.critical
25
26
You can also control individual fields like:
27
28
    env.input_L1.warning
29
    env.output.critical
30
31
=head1 MAGIC MARKERS
32
33
 #%# family=auto
34
 #%# capabilities=autoconf suggest
35
36
=head1 FEATURES
37
38
The plugin supports reporting battery charge, UPS load, input/output
39
frequencies/currents/voltages, apparent and real power output, humidity and
40
temperature readings. Note however that different UPS models report different
41
levels of detail; the plugin reports whatever information the NUT UPS driver
42
(and in turn the UPS itself) provides.
43
44
Although the 'suggest' command will only offer UPSes for which the local host
45
is the master, you can also monitor remote UPSes if you include the host name
46
in the symlink, like:
47
48
	nutups2_<upsname>@<hostname or address>_frequency
49
50
etc.
51
52
=head1 AUTHOR
53
54
Gábor Gombás <gombasg@sztaki.hu>
55
56
=head1 LICENSE
57
58
GPLv2 or later
59
60
=cut
61
62
use strict;
63
use Munin::Plugin;
64
use Carp;
65
66
my $UPSC = $ENV{'upsc'} || 'upsc';
67
68
# For the 'filter' field, the first sub-match should contain the name to
69
# display, and the second sub-match should indicate if it is a nominal
70
# value instead of a sensor reading.
71
my %config = (
72
	charge => {
73
		filter => qr/^(.*)\.(?:charge|load)$/,
74
		title => 'UPS load and battery charge',
75
		args => '--base 1000 -l 0 -u 100',
76
		vlabel => '%',
77
		config => \&common_config,
78
		fetch => \&common_fetch,
79
	},
80
	current => {
81
		filter => qr/^(.*)\.current(\.nominal)?$/,
82
		title => 'UPS current',
83
		args => '--base 1000 -l 0',
84
		vlabel => 'Amper',
85
		config => \&common_config,
86
		fetch => \&common_fetch,
87
	},
88
	frequency => {
89
		filter => qr/^(.*)\.frequency(\.nominal)?$/,
90
		title => 'UPS frequency',
91
		args => '--base 1000 -l 0',
92
		vlabel => 'Hz',
93
		config => \&common_config,
94
		fetch => \&common_fetch,
95
	},
96
	humidity => {
97
		filter => qr/^(.*)\.humidity$/,
98
		title => 'UPS humidity',
99
		args => '--base 1000 -l 0',
100
		vlabel => '%',
101
		config => \&common_config,
102
		fetch => \&common_fetch,
103
	},
104
	power => {
105
		filter => qr/^(.*)\.power(\.nominal)?$/,
106
		title => 'UPS apparent power',
107
		args => '--base 1000 -l 0',
108
		vlabel => 'VA',
109
		config => \&common_config,
110
		fetch => \&common_fetch,
111
	},
112
	realpower => {
113
		filter => qr/^(.*)\.realpower(\.nominal)?$/,
114
		title => 'UPS real power',
115
		args => '--base 1000 -l 0',
116
		vlabel => 'Watt',
117
		config => \&common_config,
118
		fetch => \&common_fetch,
119
	},
120
	temperature => {
121
		filter => qr/^(.*)\.temperature$/,
122
		title => 'UPS temperature',
123
		args => '--base 1000 -l 0',
124
		vlabel => 'Celsius',
125
		config => \&common_config,
126
		fetch => \&common_fetch,
127
	},
128
	voltage => {
129
		filter => qr/^(.*)\.voltage(\.nominal)?$/,
130
		title => 'UPS voltage',
131
		args => '--base 1000 -l 0',
132
		vlabel => 'Volt',
133
		config => \&common_config,
134
		fetch => \&common_fetch,
135
	},
136
);
137
138
sub read_ups_values {
139
	my $ups = shift;
140
141
	my @lines = `$UPSC $ups 2>/dev/null`;
142
	my $values = {};
143
	for my $line (@lines) {
144
		chomp $line;
145
146
		my ($key, $value) = $line =~ m/^([^:]+):\s+(\S.*)$/;
147
		$values->{$key} = $value;
148
	}
149
	return $values;
150
}
151
152
sub graph_config {
153
	my ($func, $ups, $values) = @_;
154
155
	print "graph_title " . $config{$func}->{'title'} . " ($ups)\n";
156
	print "graph_vlabel " . $config{$func}->{'vlabel'} . "\n";
157
	print "graph_args " . $config{$func}->{'args'} . "\n";
158
	print "graph_category sensors\n";
159
160
	my @info;
161
	push @info, 'Manufacturer: "' . $values->{'ups.mfr'} . '"'
162
		if exists $values->{'ups.mfr'} and $values->{'ups.mfr'} ne 'unknown';
163
	push @info, 'Model: "' . $values->{'ups.model'} . '"'
164
		if exists $values->{'ups.model'};
165
	push @info, 'Serial: "' . $values->{'ups.serial'} . '"'
166
		if exists $values->{'ups.serial'};
167
	map { s/\s+/ /g } @info;
168
	print "graph_info " . join(', ', @info) . "\n"
169
		if @info;
170
}
171
172
sub print_range_warning {
173
	my ($id, $key, $values) = @_;
174
175
	if (exists $values->{$key . '.minimum'}) {
176
		print $id . ".min " . $values->{$key . '.minimum'} . "\n";
177
	}
178
	if (exists $values->{$key . '.maximum'}) {
179
		print $id . ".max " . $values->{$key . '.maximum'} . "\n";
180
	}
181
182
	my $range = '';
183
	if (exists $values->{$key . '.high'}) {
184
		$range = $values->{$key . '.high'};
185
	}
186
	if (exists $values->{$key . '.low'}) {
187
		$range = $values->{$key . '.low'} . ':' . $range;
188
	}
189
	# print_thresholds() needs 'undef' for no range
190
	undef $range unless $range;
191
	print_thresholds($id, undef, undef, undef, $range);
192
}
193
194
# Example keys for voltages:
195
#	battery.voltage
196
#	battery.voltage.minimum
197
#	battery.voltage.maximum
198
#	battery.voltage.nominal
199
#	input.voltage
200
#	input.voltage.minimum
201
#	input.voltage.maximum
202
#	input.bypass.L1-N.voltage
203
#	input.L1-N.voltage
204
#	output.voltage
205
#	output.voltage.nominal
206
#	output.L1-N.voltage
207
#
208
# Replace 'voltage' with 'current' in the above list to get an example
209
# for current keys.
210
#
211
# Frequency keys:
212
#	input.frequency
213
#	input.frequency.nominal
214
#	input.bypass.frequency
215
#	input.bypass.frequency.nominal
216
#	output.frequency
217
#	output.frequency.nominal
218
#	output.frequency.minimum
219
#	output.frequency.maximum
220
sub common_config {
221
	my ($func, $ups) = @_;
222
223
	my $values = read_ups_values($ups);
224
	graph_config($func, $ups, $values);
225
	for my $key (sort keys %$values) {
226
		my ($field, $nominal) = $key =~ $config{$func}->{'filter'};
227
		next unless $field;
228
229
		$field .= $nominal if $nominal;
230
		my $id = clean_fieldname($field);
231
232
		# These labels look better this way and are still short enough
233
		$field = $key if $func =~ m/(charge|temperature|humidity)/;
234
235
		# Beautification
236
		$field = ucfirst($field);
237
		$field =~ s/\./ /g;
238
239
		print $id . ".label " . $field . "\n";
240
		print $id . ".type GAUGE\n";
241
242
		# Draw nominal values a litle thinner
243
		print $id . ".draw LINE1\n" if $nominal;
244
245
		print_range_warning($id, $key, $values);
246
	}
247
}
248
249
sub common_fetch {
250
	my ($func, $ups) = @_;
251
252
	my $values = read_ups_values($ups);
253
	for my $key (sort keys %$values) {
254
		my ($field, $nominal) = $key =~ $config{$func}->{'filter'};
255
		next unless $field;
256
257
		$field .= $nominal if $nominal;
258
		my $id = clean_fieldname($field);
259
260
		print $id . ".value " . $values->{$key} . "\n";
261
	}
262
}
263
264
if ($ARGV[0] and $ARGV[0] eq 'autoconf') {
265
	# The former nutups_ plugin parsed upsmon.conf. But for a large UPS
266
	# that powers dozens or hundreds of machines, that would mean
267
	# monitoring the same UPS from every host it powers, which does not
268
	# make sense. Using upsc and defaulting to localhost means that
269
	# 'autoconf' will only enable the plugin on the UPS master node, where
270
	# upsd is running.
271
	my @upses = `$UPSC -l 2>/dev/null`;
272
	if ($?) {
273
		if ($? == -1) {
274
			print "no (program '$UPSC' was not found)\n";
275
		}
276
		else {
277
			print "no (program '$UPSC -l' returned error)\n";
278
		}
279
		exit 0;
280
	}
281
282
	map { chomp $_ } @upses;
283
	unless (@upses and $upses[0]) {
284
		print "no (program '$UPSC' listed no units)\n";
285
	}
286
	else {
287
		print "yes\n";
288
	}
289
	exit 0;
290
}
291
292
if ($ARGV[0] and $ARGV[0] eq 'suggest') {
293
	my @upses = `$UPSC -l 2>/dev/null`;
294
	for my $ups (@upses) {
295
		chomp $ups;
296
		for my $metric (keys %config) {
297
			my $values = read_ups_values($ups);
298
			my @keys = grep { +$_ =~ $config{$metric}->{'filter'} } keys(%$values);
299
			print $ups . '_' . $metric . "\n" if @keys;
300
		}
301
	}
302
	exit 0;
303
}
304
305
croak("Unknown command line arguments") if $ARGV[0] and $ARGV[0] ne 'config';
306
307
# The UPS name may contain underscores
308
my $fn_re = join('|', keys %config);
309
my ($ups, $func) = $0 =~ m/nutups2_(.*)_($fn_re)$/;
310
311
if ($ARGV[0] and $ARGV[0] eq 'config') {
312
	$config{$func}->{'config'}($func, $ups);
313
}
314
else {
315
	$config{$func}->{'fetch'}($func, $ups);
316
}
317
318
exit 0;