mirror of
https://github.com/munin-monitoring/contrib.git
synced 2025-07-21 18:41:03 +00:00
Plugin-Gallery: Get better 2nd level headings
sensors, weather, snmp
This commit is contained in:
parent
37d658526b
commit
95de964ec9
24 changed files with 10 additions and 10 deletions
55
plugins/power/apc_status
Executable file
55
plugins/power/apc_status
Executable file
|
@ -0,0 +1,55 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# (c) Andreas Kreisl extended by Tobias Schramm
|
||||
#
|
||||
# Link name will be used as title: apc_{$title}
|
||||
#
|
||||
# env.keys LOADPCT BCHARGE LINEV BATTV TIMELEFT
|
||||
#
|
||||
|
||||
if [ -z "$keys" ]; then
|
||||
keys="LINEV LOADPCT BCHARGE NUMXFERS TIMELEFT"
|
||||
fi
|
||||
|
||||
apcinfo=`/sbin/apcaccess`
|
||||
|
||||
if [ "$1" = "config" ]; then
|
||||
title=`basename $0 | sed 's/^apc_//g' | awk '{ sub(/^./,toupper(substr($0,1,1))); print; }'`
|
||||
echo 'multigraph apc_status'
|
||||
echo "graph_title UPS Status - $title"
|
||||
echo 'graph_args --base 1000'
|
||||
echo 'graph_category sensors'
|
||||
title=`/sbin/apcaccess | egrep "^MODEL" | awk '{print $3" "$4" "$5" "$6" "$7" "$8" "$9;}'`
|
||||
echo "graph_info $title"
|
||||
for key in $keys; do
|
||||
echo "$key.label $key"
|
||||
echo "$key.info Value of $key"
|
||||
echo "$key.draw LINE1"
|
||||
done
|
||||
for key in $keys; do
|
||||
key_lower=`echo "$key" | awk '{print tolower($0);}'`
|
||||
unit=`echo "$apcinfo" | egrep "^$key" | awk '{print $4;}'`
|
||||
echo "multigraph apc_status.$key_lower"
|
||||
echo "graph_title $key"
|
||||
echo 'graph_args --base 1000'
|
||||
if [ -n "$unit" ]; then
|
||||
echo "graph_vlabel $unit"
|
||||
fi
|
||||
echo 'graph_category sensors'
|
||||
echo "$key.label $key"
|
||||
echo "$key.info $key."
|
||||
echo "$key.draw LINE1"
|
||||
done
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo 'multigraph apc_status'
|
||||
for key in $keys; do
|
||||
echo "$apcinfo" | egrep "^$key" | awk '{print $1".value "$3;}'
|
||||
done
|
||||
for key in $keys; do
|
||||
key_lower=`echo "$key" | awk '{print tolower($0)}'`
|
||||
echo "multigraph apc_status.$key_lower"
|
||||
echo "$apcinfo" | egrep "^$key" | awk '{print $1".value "$3;}'
|
||||
done
|
||||
|
259
plugins/power/apcupsd_pct
Executable file
259
plugins/power/apcupsd_pct
Executable file
|
@ -0,0 +1,259 @@
|
|||
#!/usr/bin/env perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Carp;
|
||||
use Pod::Usage;
|
||||
|
||||
our $APCACCESS = $ENV{apcaccess} || "/sbin/apcaccess";
|
||||
our $UPS_MODEL = $ENV{ups_model} || "ES 725";
|
||||
our $VERSION = 1.0;
|
||||
my %Graph;
|
||||
my %Metric;
|
||||
|
||||
MAIN: {
|
||||
decide_monitor_type();
|
||||
|
||||
my $mode = $ARGV[0] || "fetch";
|
||||
$mode =~ /^-/ && pod2usage();
|
||||
|
||||
### $mode
|
||||
eval "do_${mode}();"
|
||||
or croak "do_${mode}: $@";
|
||||
|
||||
### end
|
||||
exit 0;
|
||||
}
|
||||
|
||||
=begin comment
|
||||
|
||||
pct
|
||||
LOADPCT is the percentage of load capacity as estimated by the UPS.
|
||||
15.0 Percent Load Capacity
|
||||
BCHARGE is the percentage charge on the batteries.
|
||||
100.0 Percent
|
||||
|
||||
volt
|
||||
LINEV is the current line voltage as returned by the UPS.
|
||||
102.0 Volts
|
||||
BATTV is the battery voltage as supplied by the UPS.
|
||||
13.5 Volts
|
||||
|
||||
time
|
||||
TIMELEFT is the remaining runtime left on batteries as estimated by the UPS.
|
||||
38.4 Minutes
|
||||
|
||||
pwr
|
||||
LOADPCT is the percentage of load capacity as estimated by the UPS.
|
||||
15.0 Percent Load Capacity
|
||||
NOMPOWER
|
||||
330 Watts
|
||||
LOADMETRIC=LOADPCT/100*NOMPOWER gives realtime power consumption in WATTS
|
||||
|
||||
=end comment
|
||||
|
||||
=cut
|
||||
|
||||
sub decide_monitor_type {
|
||||
my $type = $0 =~ /_pct/ ? "pct" :
|
||||
$0 =~ /_volt/ ? "volt" :
|
||||
$0 =~ /_time/ ? "time" :
|
||||
$0 =~ /_pwr/ ? "pwr" : undef
|
||||
or croak "unknown monitor type: $0";
|
||||
|
||||
# common
|
||||
%Graph = (
|
||||
graph_title => "APC Status".($UPS_MODEL?" ($UPS_MODEL)":"")." - ",
|
||||
graph_category => "sensors",
|
||||
graph_info => "This graph shows information about your APC UPS",
|
||||
graph_args => "--base 1000 --lower-limit 0",
|
||||
);
|
||||
|
||||
if ($type eq "pct") {
|
||||
$Graph{graph_title} .= "Percentage";
|
||||
$Graph{graph_vlabel} = "%";
|
||||
%Metric =(
|
||||
LOADPCT => {
|
||||
label => "load capacity pct",
|
||||
},
|
||||
BCHARGE => {
|
||||
label => "charge on the batteries pct",
|
||||
},
|
||||
);
|
||||
} elsif ($type eq "volt") {
|
||||
$Graph{graph_title} .= "Voltage";
|
||||
$Graph{graph_vlabel} = "Volts";
|
||||
%Metric =(
|
||||
LINEV => {
|
||||
label => "line voltage as returned by the UPS",
|
||||
},
|
||||
BATTV => {
|
||||
label => "battery voltage as supplied by the UPS",
|
||||
},
|
||||
);
|
||||
} elsif ($type eq "time") {
|
||||
$Graph{graph_title} .= "Time";
|
||||
$Graph{graph_vlabel} = "minutes";
|
||||
%Metric =(
|
||||
TIMELEFT => {
|
||||
label => "remaining runtime left on batteries",
|
||||
},
|
||||
);
|
||||
} elsif ($type eq "pwr") {
|
||||
$Graph{graph_title} .= "Power";
|
||||
$Graph{graph_vlabel} = "watts";
|
||||
%Metric =(
|
||||
LOADMETRIC => {
|
||||
label => "absolute power consumption",
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
sub do_fetch {
|
||||
### do_fetch
|
||||
|
||||
my @status_data = retrieve_apcupsd_status()
|
||||
or croak "failed: retrieve_apcupsd_status";
|
||||
### status_data: \@status_data
|
||||
|
||||
my $status = parse_status_data(@status_data);
|
||||
### status: $status
|
||||
my $prod_status = proccess_status($status);
|
||||
|
||||
my $FIELD;
|
||||
while (my($field,$attr) = each %Metric) {
|
||||
$field = lc $field;
|
||||
$FIELD = uc $field;
|
||||
printf "%s.value %.1f\n", $field, (exists $status->{$FIELD} ? ($status->{$FIELD} =~ /([\d]+\.?[\d]*)/) : ( exists $prod_status->{$FIELD} ? ( $prod_status->{$FIELD} =~ /([\d]+\.?[\d]*)/) : 0 ) );
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub do_config {
|
||||
### do_config
|
||||
|
||||
while (my($k,$v) = each %Graph) {
|
||||
printf "%s %s\n", $k, $v;
|
||||
}
|
||||
while (my($field,$attr) = each %Metric) {
|
||||
$field = lc $field;
|
||||
while (my($k,$v) = each %$attr) {
|
||||
printf "%s.%s %s\n", $field, $k, $v;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub do_autoconf {
|
||||
### do_config
|
||||
print "yes\n";
|
||||
}
|
||||
|
||||
sub retrieve_apcupsd_status {
|
||||
open my $apc, '-|', $APCACCESS
|
||||
or croak $!;
|
||||
my @status_data = <$apc>;
|
||||
close $apc;
|
||||
chomp @status_data;
|
||||
return @status_data;
|
||||
}
|
||||
|
||||
sub proccess_status {
|
||||
my $prod = {};
|
||||
my($status) = @_;
|
||||
|
||||
if (exists $status->{NOMPOWER} && exists $status->{LOADPCT}) {
|
||||
my $pwr_pct = sprintf "%.1f", ($status->{LOADPCT} =~ /([\d]+\.?[\d]*)/) ;
|
||||
my $nom_pwr = sprintf "%.1f", ($status->{NOMPOWER} =~ /([\d]+\.?[\d]*)/) ;
|
||||
$prod->{LOADMETRIC} = $pwr_pct/100 * $nom_pwr ;
|
||||
}
|
||||
|
||||
return $prod;
|
||||
}
|
||||
|
||||
sub parse_status_data {
|
||||
my $status = {};
|
||||
my($k,$v);
|
||||
for (@_) {
|
||||
($k,$v) = split /\s*:\s*/, $_, 2;
|
||||
$status->{$k} = $v;
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
B<apcupsd_pct>, B<apcupsd_volt>, B<apcupsd_time>, B<apcupsd_pwr>- munin plugin for APC UPS
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<apcupsd_pct> [ I<config>|I<fetch> ]
|
||||
|
||||
B<apcupsd_volt> [ I<config>|I<fetch> ]
|
||||
|
||||
B<apcupsd_time> [ I<config>|I<fetch> ]
|
||||
|
||||
B<apcupsd_pwr> [ I<config>|I<fetch> ]
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
munin plugin to monitor APC UPS via apcupsd by apcaccess.
|
||||
|
||||
=head1 INSTALLATION
|
||||
|
||||
cp apcupsd_pct $MUNIN_LIBDIR/plugsin/
|
||||
|
||||
cd YOUR_MUNIN_PLUGINS_DIR
|
||||
(make symbolic links different name)
|
||||
ln -s $MUNIN_LIBDIR/plugsin/apcupsd_pct apcupsd_pct
|
||||
ln -s $MUNIN_LIBDIR/plugsin/apcupsd_pct apcupsd_volt
|
||||
ln -s $MUNIN_LIBDIR/plugsin/apcupsd_pct apcupsd_time
|
||||
ln -s $MUNIN_LIBDIR/plugsin/apcupsd_pwr apcupsd_pwr
|
||||
|
||||
restart munin-node
|
||||
|
||||
=head1 REPOSITORY
|
||||
|
||||
L<http://github.com/hirose31/munin-apcupsd>
|
||||
|
||||
git clone git://github.com/hirose31/munin-apcupsd.git
|
||||
|
||||
patches and collaborators are welcome.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<http://exchange.munin-monitoring.org/plugins/apcupsd_pct/details>
|
||||
|
||||
L<http://munin.projects.linpro.no/wiki/HowToWritePlugins>,
|
||||
L<http://munin.projects.linpro.no/wiki/protocol-config>
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
HIROSE, Masaaki E<lt>hirose31 _at_ gmail.comE<gt>
|
||||
|
||||
=head1 CHANGELOG
|
||||
|
||||
* 10/11/2010 - basos - added support for absolute power display
|
||||
|
||||
=head1 COPYRIGHT & LICENSE
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the same terms as Perl itself.
|
||||
|
||||
=cut
|
||||
|
||||
# for Emacsen
|
||||
# Local Variables:
|
||||
# mode: cperl
|
||||
# cperl-indent-level: 4
|
||||
# indent-tabs-mode: nil
|
||||
# coding: utf-8
|
||||
# End:
|
||||
|
||||
# vi: set ts=4 sw=4 sts=0 :
|
343
plugins/power/apcupsd_ww
Executable file
343
plugins/power/apcupsd_ww
Executable file
|
@ -0,0 +1,343 @@
|
|||
#!/usr/bin/perl -w
|
||||
#
|
||||
# Plugin to monitor apcupsd via apcaccess
|
||||
#
|
||||
# Version 1.3
|
||||
#
|
||||
# Copyright (C) 2005-2008 Behan Webster <behanw AT websterwood DOT com>
|
||||
# Licenced under GPL 2.0
|
||||
#
|
||||
# Written by: Behan Webster <behanw AT websterwood DOT com>
|
||||
# German translation by: Bianco Veigel <bianco.veigel AT zivillian DOT de>
|
||||
#
|
||||
#%# family=auto
|
||||
#%# capabilities=autoconf
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use vars qw(%attrs %data %num);
|
||||
|
||||
my $apcaccess='/sbin/apcaccess';
|
||||
#$apcaccess='/home/behanw/bin/apcaccess';
|
||||
my $config='/etc/munin/plugin-conf.d/apcupsd_ww';
|
||||
|
||||
my $language = $ENV{LANG} || 'en';
|
||||
|
||||
# Example apcaccess output
|
||||
# KEY : VALUE
|
||||
#
|
||||
# UPSNAME : Elfhild
|
||||
# MODEL : SMART-UPS 1400 RM XL
|
||||
# STATUS : ONLINE
|
||||
# LINEV : 123.5 Volts
|
||||
# LOADPCT : 24.9 Percent Load Capacity
|
||||
# BCHARGE : 100.0 Percent
|
||||
# TIMELEFT : 63.0 Minutes
|
||||
# OUTPUTV : 123.5 Volts
|
||||
# ITEMP : 39.1 C Internal
|
||||
# BATTV : 54.5 Volts
|
||||
# NOMOUTV : 115 Volts
|
||||
# NOMBATTV : 48.0 Volts
|
||||
|
||||
# Possible values to graph in munin
|
||||
# Only the ones which are available will be graphed
|
||||
%attrs = (
|
||||
# APCACCESS_KEY => {
|
||||
# name => 'attribute_name',
|
||||
# label => {
|
||||
# en => 'English title',
|
||||
# de => 'Titel in Deutsch',
|
||||
# fr => 'titre en Francais',
|
||||
# },
|
||||
# type => 'name_of_functio_for_type', # Default is 'num'
|
||||
# # Can use one value, or list of values. If the first value can't be used, try the next.
|
||||
# # KEY Key from apcaccess
|
||||
# # num,num,num Specify a list of possible nominal values to guess from
|
||||
# # num Specify fixed nominal value
|
||||
# nominal => [ 'KEY', '100' ],
|
||||
# # KEY Key from apcaccess
|
||||
# # +-num% Calculate percentage min:max from nominal value
|
||||
# # +-num Calculate min:max from nominal value
|
||||
# # -num:+num Calculate min:max from nominal value
|
||||
# # num:num Specify fixed min:max values
|
||||
# # num or :num Specify fixed max value
|
||||
# # num: Specify fixed min value
|
||||
# warning => [ 'KEY:KEY', '+-10%', '-10:+15' ],
|
||||
# critical => [ 'KEY:KEY', '+-10%', '-10:+15' ],
|
||||
# },
|
||||
BCHARGE => { # BCHARGE : 100.0 Percent
|
||||
name => 'battery',
|
||||
label => {
|
||||
en => 'Percent battery charge',
|
||||
de => 'Batterieladung in Prozent',
|
||||
},
|
||||
warning => '33:', # %
|
||||
critical => '5:', # %
|
||||
},
|
||||
LOADPCT => { # LOADPCT : 28.6 Percent Load Capacity
|
||||
name => 'upsload',
|
||||
label => {
|
||||
en => 'Percent load capacity',
|
||||
de => 'Auslastung in Prozent',
|
||||
},
|
||||
warning => '75', # %
|
||||
critical => '90', # %
|
||||
},
|
||||
TIMELEFT => { # TIMELEFT : 17.0 Minutes
|
||||
name => 'timeleft',
|
||||
label => {
|
||||
en => 'Minutes of run time',
|
||||
de => 'Akkulaufzeit in Minuten',
|
||||
},
|
||||
warning => '5:', # mins
|
||||
critical => [ 'DLOWBATT:', '2:' ], # DLOWBATT : 02 Minutes
|
||||
},
|
||||
LINEV => { # LINEV : 121.5 Volts
|
||||
name => 'linevolts',
|
||||
label => {
|
||||
en => 'Line voltage',
|
||||
de => 'Eingangsspannung',
|
||||
},
|
||||
nominal => [ 'NOMINV', 'NOMOUTV', '115,230' ], # NA=115V, Europe=230V
|
||||
warning => [ '+-10%', '108:128' ],
|
||||
critical => [ 'LOTRANS:HITRANS', '+-15%', '104:132' ],
|
||||
},
|
||||
BATTV => { # BATTV : 27.7 Volts
|
||||
name => 'batteryvolts',
|
||||
label => {
|
||||
en => 'Battery voltage',
|
||||
de => 'Batteriespannung',
|
||||
},
|
||||
nominal => [ 'NOMBATTV', '12,24,48' ], # NOMBATTV : 48.0 Volts
|
||||
warning => '-5%:+15%',
|
||||
critical => '-10%:+25%',
|
||||
},
|
||||
OUTPUTV => { # OUTPUTV : 122.2 Volts
|
||||
name => 'outputvolts',
|
||||
label => {
|
||||
en => 'Output voltage',
|
||||
de => 'Ausgangsspannung',
|
||||
},
|
||||
nominal => [ 'NOMOUTV', '115,230' ], # NOMOUTV : 115 Volts
|
||||
warning => [ '+-10%', '108:128' ],
|
||||
critical => [ 'LOTRANS:HITRANS', '+-15%', '104:132' ],
|
||||
},
|
||||
ITEMP => { # ITEMP : 44.1 C Internal
|
||||
name => 'temperature',
|
||||
label => {
|
||||
en => 'UPS temperature',
|
||||
de => 'USV Temperatur',
|
||||
},
|
||||
warning => 50, # C
|
||||
critical => 60, # C
|
||||
},
|
||||
LINEFAIL => { # LINEFAIL : OK
|
||||
name => 'linefail',
|
||||
label => {
|
||||
en => 'Line voltage status',
|
||||
de => 'Status Eingangsspannung',
|
||||
},
|
||||
type => 'bool',
|
||||
critical => '0:', # Failed
|
||||
},
|
||||
BATTSTAT => { # BATTSTAT : OK
|
||||
name => 'battstat',
|
||||
label => {
|
||||
en => 'Battery status',
|
||||
de => 'Batteriestatus',
|
||||
},
|
||||
type => 'bool',
|
||||
critical => '0:', # Failed
|
||||
},
|
||||
MAINS => { # MAINS : OK
|
||||
name => 'mains',
|
||||
label => {
|
||||
en => 'Mains status',
|
||||
de => 'Status Eingangsspannung',
|
||||
},
|
||||
type => 'bool',
|
||||
critical => '0:', # Failed
|
||||
},
|
||||
#STATUS => { # STATUS : ONLINE
|
||||
# name => 'status',
|
||||
# label => {
|
||||
# en => 'Status',
|
||||
# },
|
||||
# type => 'status',
|
||||
# critical => 0,
|
||||
#},
|
||||
);
|
||||
|
||||
# Read config file
|
||||
# Can be used to override settings in %attrs
|
||||
if (-f $config) {
|
||||
require $config;
|
||||
}
|
||||
|
||||
# Determine plugin capabilities
|
||||
if (defined $ARGV[0] && $ARGV[0] =~ /autoconf|detect/) {
|
||||
if (-x $apcaccess) {
|
||||
print "yes\n";
|
||||
exit 0;
|
||||
} else {
|
||||
print "no (apcaccess not found)\n";
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
|
||||
# Read info from apcupsd using apcaccess
|
||||
die "$apcaccess: not found\n" unless -x $apcaccess;
|
||||
open (APCACCESS, "$apcaccess 2>&1 |") || die "$apcaccess: $!\n";
|
||||
while (<APCACCESS>) {
|
||||
chomp;
|
||||
die "$apcaccess: $_\n" if /Error contacting apcupsd/;
|
||||
$data{$1} = $2 if /^(\S+?)\s*:\s+(.+?)$/;
|
||||
$num{$1} = $2 if /^(\S+?)\s*:\s+([\d.x]+)/;
|
||||
}
|
||||
close APCACCESS;
|
||||
|
||||
# Auto-configure plugin
|
||||
if (defined $ARGV[0] && $ARGV[0] eq 'config') {
|
||||
if (defined $data{UPSNAME}) {
|
||||
print "graph_title $data{UPSNAME} ($data{MODEL})\n";
|
||||
} else {
|
||||
print "graph_title $data{MODEL}\n";
|
||||
}
|
||||
#print "graph_vlabel Units\n";
|
||||
print "graph_category sensors\n";
|
||||
print "graph_info This graph shows information about your APC uninterruptible power supply.\n";
|
||||
|
||||
foreach my $what (sort keys %attrs) {
|
||||
&label("$what");
|
||||
}
|
||||
|
||||
# Print current values
|
||||
} else {
|
||||
foreach my $what (sort keys %attrs) {
|
||||
next unless defined $data{$what};
|
||||
my $func = $attrs{$what}{type} || 'num';
|
||||
my $value = eval "\&$func('$what')";
|
||||
print "$attrs{$what}{name}.value $value\n";
|
||||
}
|
||||
}
|
||||
|
||||
exit 0;
|
||||
|
||||
##############################################################################
|
||||
# Print label/title for value
|
||||
sub label {
|
||||
my $what = shift;
|
||||
return unless defined $data{$what};
|
||||
|
||||
my $attr = $attrs{$what};
|
||||
|
||||
# Determine language to use for labels
|
||||
my $lang = $language;
|
||||
$lang =~ s/_.*$// unless defined $attr->{label}{$lang};
|
||||
# Failback to english if translation isn't available
|
||||
$lang = 'en' unless defined $attr->{label}{$lang};
|
||||
|
||||
print "$attr->{name}.label $attr->{label}{$lang}\n";
|
||||
&info($what, 'warning');
|
||||
&info($what, 'critical');
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
# Makes a scalar or array into an array (used in &info)
|
||||
sub list {
|
||||
return (ref($_[0]) eq 'ARRAY') ? @{$_[0]} : @_;
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
# Used to setup warning or critical levels for munin
|
||||
sub info {
|
||||
my $what = shift;
|
||||
my $level = shift; # 'warning' or 'critical'
|
||||
|
||||
my $attr = $attrs{$what};
|
||||
return unless defined $attr->{$level};
|
||||
|
||||
# Determine nominal value for info calculation
|
||||
my $nom = undef;
|
||||
if (defined $attr->{nominal}) {
|
||||
for my $n (&list($attr->{nominal})) {
|
||||
# Guess list: compare guesses to value of $num{$what}
|
||||
if ($n =~ /,/) {
|
||||
my $fitness = ~0;
|
||||
next unless $num{$what};
|
||||
foreach my $possibility (split /[,\s]+/, $n) {
|
||||
my $diff = abs($num{$what} - $possibility);
|
||||
($nom, $fitness) = ($possibility, $diff) if $fitness >= $diff;
|
||||
}
|
||||
|
||||
# Absolute nominal value
|
||||
} elsif ($n =~ /^[\d.]+$/) {
|
||||
$nom = $n;
|
||||
last;
|
||||
|
||||
# Lookup nominal value as an APCUPSD key
|
||||
} elsif (defined $num{$n}) {
|
||||
$nom = $num{$n};
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Calculate info value for $level
|
||||
foreach my $value (&list($attr->{$level})) {
|
||||
$value =~ s/([^:]+)/&calc($1,$nom)/eg;
|
||||
if ($value =~ /^[\d.:]+$/) {
|
||||
print "$attr->{name}.$level $value\n";
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
# Change warning/critical ranges into numbers for munin
|
||||
sub calc {
|
||||
my $v = shift;
|
||||
my $nom = shift;
|
||||
|
||||
return $v if $v =~ /^[\d.]+$/;
|
||||
return $num{$v} if defined $num{$v};
|
||||
return '' unless defined $nom;
|
||||
if ($v =~ /^\+-([\d.]+)%$/) {
|
||||
return sprintf "%.0f:%.0f", (100 - $1) * $nom / 100, (100 + $1) * $nom / 100;
|
||||
} elsif ($v =~ /^([-+][\d.]+)%$/) {
|
||||
return sprintf "%.0f", (100 + $1) * $nom / 100;
|
||||
} elsif ($v =~ /^\+-([\d.]+)$/) {
|
||||
return sprintf "%d:%d", $nom - $1, $nom + $1;
|
||||
} elsif ($v =~ /^([-+][\d.]+)$/) {
|
||||
return $nom + $1;
|
||||
} elsif ($v =~ /^\*([\d.]+)$/) {
|
||||
return $nom * $1;
|
||||
} elsif ($v =~ /^\/([\d.]+)$/) {
|
||||
return sprintf "%.0f", $nom / $1;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
# Default "type" routine to display values
|
||||
sub num {
|
||||
my $what = shift;
|
||||
return $num{$what};
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
# "type" routine to change Ok/Not Ok into 1/0
|
||||
sub bool {
|
||||
my $what = shift;
|
||||
return $num{$what} eq "OK" ? "1" : "0";
|
||||
}
|
||||
|
||||
#sub status {
|
||||
# my $what = shift;
|
||||
# return unless defined $data{$what};
|
||||
# print "$attrs{$what}{name}.value ";
|
||||
# print $num{$what} eq "ONLINE" ? "1" : "0";
|
||||
# print "\n";
|
||||
#}
|
||||
|
||||
# vim: sw=4 ts=4
|
281
plugins/power/eatonups_
Normal file
281
plugins/power/eatonups_
Normal file
|
@ -0,0 +1,281 @@
|
|||
#!/bin/sh
|
||||
|
||||
###################################################################################################
|
||||
#
|
||||
# Multigraph munin plugin to monitor Eaton UPS-es through the web interface of the SNMP add-on card.
|
||||
# The plugin script simply parses the /PSummary.html page and extracts the values from there.
|
||||
#
|
||||
# To use this plugin, copy it to the munin's plugin directory (eg. /usr/share/munin/plugins)
|
||||
# under the name "eatonups_". Don't change this filename! Follow these steps:
|
||||
#
|
||||
# 1. Give names to your UPSes, in fqdn style. Like "ups.server1" or "ups.server2". Make sure
|
||||
# you can resolve these names as DNS names from the munin machine. You can simply add them
|
||||
# as entries in /etc/hosts.
|
||||
#
|
||||
# 2. Then symlink it to munin's configured plugins directory (eg. /etc/munin/plugins) with names
|
||||
# according to the devices you wish to monitor, eg:
|
||||
#
|
||||
# eatonups_ups.server1
|
||||
# eatonups_ups.server2
|
||||
#
|
||||
# 3. In /etc/munin/munin.conf just add these lines for them. Yes, 127.0.0.1 is correct
|
||||
# because that points to the munin-node address not the UPS address.
|
||||
#
|
||||
# [eatonups_ups.server1]
|
||||
# address 127.0.0.1
|
||||
#
|
||||
# [eatonups_ups.server2]
|
||||
# address 127.0.0.1
|
||||
#
|
||||
# 4. Restart the munin node by 'service munin-node restart'.
|
||||
#
|
||||
# If all went well, after 5 minutes or so you should have two additional nodes listed
|
||||
# on the Web Interface of munin.
|
||||
#
|
||||
# Tested & working with Eaton USP model PW9130 1500VA-R, with installed ConnectUPS Web/SNMP Card
|
||||
# firmware revision V4.36 with munin v.2.0.14 and Ubuntu LTS 12.04
|
||||
# Created in 2013 by robi
|
||||
# v0.2 - fixed frequency graph scale to center at 50Hz (correct value for Europe)
|
||||
# v0.1 - initial version
|
||||
##################################################################################################
|
||||
|
||||
case $0 in
|
||||
*eatonups_*)
|
||||
hostname=${0##*/eatonups_}
|
||||
;;
|
||||
esac
|
||||
|
||||
case $1 in
|
||||
config)
|
||||
|
||||
echo "multigraph volt_ac"
|
||||
echo "host_name $hostname"
|
||||
echo "graph_args --base 1000"
|
||||
echo "graph_title AC Voltage Mains"
|
||||
echo "graph_vlabel Volts"
|
||||
echo "graph_category sensors"
|
||||
echo "graph_scale no"
|
||||
echo "graph_info Input and Output voltage of the UPS."
|
||||
echo "volt_in.label Input"
|
||||
echo "volt_in.critical 210:250"
|
||||
echo "volt_in.info Input mains voltage of the UPS."
|
||||
echo "volt_out.label Output"
|
||||
echo "volt_out.critical 210:250"
|
||||
echo "volt_out.info Output mains voltage of the UPS."
|
||||
echo
|
||||
echo "multigraph volt_batt"
|
||||
echo "host_name $hostname"
|
||||
echo "graph_args --base 1000"
|
||||
echo "graph_title DC Voltage Battery"
|
||||
echo "graph_vlabel Volts"
|
||||
echo "graph_category sensors"
|
||||
echo "graph_scale no"
|
||||
echo "graph_info Voltage of the internal battery of the UPS."
|
||||
echo "volt_batt.label Battery"
|
||||
echo "volt_batt.critical 45:65"
|
||||
echo "volt_batt.info Battery voltage of the UPS."
|
||||
echo
|
||||
echo "multigraph curr_out"
|
||||
echo "host_name $hostname"
|
||||
echo "graph_args --base 1000"
|
||||
echo "graph_title Output Current"
|
||||
echo "graph_vlabel Ampers"
|
||||
echo "graph_category sensors"
|
||||
echo "graph_scale no"
|
||||
echo "graph_info Output current of the UPS."
|
||||
echo "curr_out.label Current"
|
||||
echo "curr_out.critical 40"
|
||||
echo "curr_out.info Output current of the UPS."
|
||||
echo
|
||||
echo "multigraph power"
|
||||
echo "host_name $hostname"
|
||||
echo "graph_args --base 1000"
|
||||
echo "graph_title Power"
|
||||
echo "graph_vlabel W or VA"
|
||||
echo "graph_category sensors"
|
||||
echo "graph_scale no"
|
||||
echo "graph_info Output Power of the UPS."
|
||||
echo "power_true.label True"
|
||||
echo "power_true.critical 800"
|
||||
echo "power_true.info True Power output of the UPS (Watts)."
|
||||
echo "power_appr.label Apparent"
|
||||
echo "power_appr.critical 1500"
|
||||
echo "power_appr.info Apparent Power output of the UPS (VA)."
|
||||
echo
|
||||
echo "multigraph runtime"
|
||||
echo "host_name $hostname"
|
||||
echo "graph_args --base 1000"
|
||||
echo "graph_title Runtime"
|
||||
echo "graph_vlabel minutes"
|
||||
echo "graph_category sensors"
|
||||
echo "graph_scale no"
|
||||
echo "graph_info Remaining runtime of the UPS."
|
||||
echo "runtime.label Runtime"
|
||||
echo "runtime.critical 30:"
|
||||
echo "runtime.info Remaining runtime of the UPS (minutes)."
|
||||
echo
|
||||
echo "multigraph load"
|
||||
echo "host_name $hostname"
|
||||
echo "graph_args --base 1000"
|
||||
echo "graph_title Load"
|
||||
echo "graph_vlabel %"
|
||||
echo "graph_category sensors"
|
||||
echo "graph_scale no"
|
||||
echo "graph_info Load of the UPS."
|
||||
echo "load.label Load"
|
||||
echo "load.critical 60"
|
||||
echo "load.info Load of the UPS (percent)."
|
||||
echo
|
||||
echo "multigraph freq_in"
|
||||
echo "host_name $hostname"
|
||||
echo "graph_args --base 1000 -l 48.8 -u 51.2 --rigid --alt-y-grid"
|
||||
echo "graph_title Frequency Input"
|
||||
echo "graph_vlabel Hz"
|
||||
echo "graph_category sensors"
|
||||
echo "graph_scale no"
|
||||
echo "graph_info Input frequency of the UPS."
|
||||
echo "freq_in.label Hz in"
|
||||
echo "freq_in.critical 49:51"
|
||||
echo "freq_in.info Input frequency of the UPS."
|
||||
echo
|
||||
echo "multigraph freq_out"
|
||||
echo "host_name $hostname"
|
||||
echo "graph_args --base 1000 -l 48.8 -u 51.2 --rigid --alt-y-grid"
|
||||
echo "graph_title Frequency Output"
|
||||
echo "graph_vlabel Hz"
|
||||
echo "graph_category sensors"
|
||||
echo "graph_scale no"
|
||||
echo "graph_info Output frequency of the UPS."
|
||||
echo "freq_out.label Hz out"
|
||||
echo "freq_out.critical 49:51"
|
||||
echo "freq_out.info Output frequency of the UPS."
|
||||
echo
|
||||
echo "multigraph temp"
|
||||
echo "host_name $hostname"
|
||||
echo "graph_args --base 1000"
|
||||
echo "graph_title Temperature"
|
||||
echo "graph_vlabel degrees Celsius"
|
||||
echo "graph_category sensors"
|
||||
echo "graph_scale no"
|
||||
echo "graph_info Internal Temperature of the UPS."
|
||||
echo "temp.label Load"
|
||||
echo "temp.critical 80"
|
||||
echo "temp.info Internal Temperature of the UPS (degrees Celsius)."
|
||||
echo
|
||||
|
||||
exit 0;;
|
||||
esac
|
||||
|
||||
statusfile=/tmp/eatonups_munin_$hostname.html
|
||||
|
||||
wget -O $statusfile http://$hostname/PSummary.html -o /dev/null --timeout 9
|
||||
|
||||
if [ -f "$statusfile" ]
|
||||
then
|
||||
volt_in=`sed -n -e '/Voltage In/{n;p;}' $statusfile | sed 's/<[^>]*>//g'`
|
||||
volt_out=`sed -n -e '/Voltage Out/{n;p;}' $statusfile | sed 's/<[^>]*>//g'`
|
||||
volt_batt=`sed -n -e '/Voltage</{n;p;}' $statusfile | sed 's/<[^>]*>//g'`
|
||||
curr_out=`sed -n -e '/Current Out/{n;p;}' $statusfile | sed 's/<[^>]*>//g'`
|
||||
power_true=`sed -n -e '/True Power/{n;p;}' $statusfile | sed 's/<[^>]*>//g'`
|
||||
power_appr=`sed -n -e '/Apparent Power/{n;p;}' $statusfile | sed 's/<[^>]*>//g'`
|
||||
runtime=`sed -n -e '/Runtime/{n;p;}' $statusfile | sed 's/<[^>]*>//g'`
|
||||
freq_in=`sed -n -e '/Frequency/{n;p;}' $statusfile | sed 's/<[^>]*>//g' | sed -n '1p'`
|
||||
freq_out=`sed -n -e '/Frequency/{n;p;}' $statusfile | sed 's/<[^>]*>//g' | sed -n '2p'`
|
||||
load=`sed -n -e '/UPS Load/{n;p;}' $statusfile | sed 's/<[^>]*>//g'`
|
||||
temp=`sed -n -e '/UPS Internal Temperature/{n;p;}' $statusfile | sed 's/<[^>]*>//g'`
|
||||
|
||||
rm -f $statusfile
|
||||
fi
|
||||
|
||||
echo "multigraph volt_ac"
|
||||
echo -n "volt_in.value "
|
||||
if [ -n "$volt_in" ]; then
|
||||
echo "$volt_in"
|
||||
else
|
||||
echo "U"
|
||||
fi
|
||||
echo -n "volt_out.value "
|
||||
if [ -n "$volt_out" ]; then
|
||||
echo "$volt_out"
|
||||
else
|
||||
echo "U"
|
||||
fi
|
||||
echo
|
||||
|
||||
echo "multigraph volt_batt"
|
||||
echo -n "volt_batt.value "
|
||||
if [ -n "$volt_batt" ]; then
|
||||
echo "$volt_batt"
|
||||
else
|
||||
echo "U"
|
||||
fi
|
||||
echo
|
||||
|
||||
echo "multigraph curr_out"
|
||||
echo -n "curr_out.value "
|
||||
if [ -n "$curr_out" ]; then
|
||||
echo "$curr_out"
|
||||
else
|
||||
echo "U"
|
||||
fi
|
||||
echo
|
||||
|
||||
echo "multigraph power"
|
||||
echo -n "power_true.value "
|
||||
if [ -n "$power_true" ]; then
|
||||
echo "$power_true"
|
||||
else
|
||||
echo "U"
|
||||
fi
|
||||
echo -n "power_appr.value "
|
||||
if [ -n "$power_appr" ]; then
|
||||
echo "$power_appr"
|
||||
else
|
||||
echo "U"
|
||||
fi
|
||||
echo
|
||||
|
||||
echo "multigraph runtime"
|
||||
echo -n "runtime.value "
|
||||
if [ -n "$runtime" ]; then
|
||||
echo "$runtime"
|
||||
else
|
||||
echo "U"
|
||||
fi
|
||||
echo
|
||||
|
||||
echo "multigraph load"
|
||||
echo -n "load.value "
|
||||
if [ -n "$load" ]; then
|
||||
echo "$load"
|
||||
else
|
||||
echo "U"
|
||||
fi
|
||||
echo
|
||||
|
||||
echo "multigraph freq_in"
|
||||
echo -n "freq_in.value "
|
||||
if [ -n "$freq_in" ]; then
|
||||
echo "$freq_in"
|
||||
else
|
||||
echo "U"
|
||||
fi
|
||||
echo
|
||||
|
||||
echo "multigraph freq_out"
|
||||
echo -n "freq_out.value "
|
||||
if [ -n "$freq_out" ]; then
|
||||
echo "$freq_out"
|
||||
else
|
||||
echo "U"
|
||||
fi
|
||||
echo
|
||||
|
||||
echo "multigraph temp"
|
||||
echo -n "temp.value "
|
||||
if [ -n "$temp" ]; then
|
||||
echo "$temp"
|
||||
else
|
||||
echo "U"
|
||||
fi
|
||||
echo
|
93
plugins/power/nut
Executable file
93
plugins/power/nut
Executable file
|
@ -0,0 +1,93 @@
|
|||
#!/bin/bash
|
||||
# This script is intended for use with Munin to monitor
|
||||
# UPS Load, Battery Charge, Input and Output Voltages
|
||||
# querying data from NUT (www.networkupstools.org), tested under Ubuntu Linux
|
||||
# v. 1.1, 12/16/2007
|
||||
# (c) Alex Yanchenko (yanchenko{at}gmail.com), 2007
|
||||
# Distributed under GPL v.3 (http://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
#
|
||||
# The plugin can utilize automatic configuration,
|
||||
# here are the basic steps (require root privileges):
|
||||
# 1. Copy it as /usr/share/munin/plugins/nut_
|
||||
# 2. Make executable: "chmod 755 /usr/share/munin/plugins/nut_"
|
||||
# 3. Run "munin-node-configure --shell", you should see smth like
|
||||
# "ln -s /usr/share/munin/plugins/nut_ /etc/munin/plugins/nut_apc_AT_localhost"
|
||||
# with "apc@localhost" been UPS configured in upsmon.conf (see NUT docs).
|
||||
# Note that "@" is replaced with "_AT_".
|
||||
# Multiple UPS monitoring is supported as well.
|
||||
# 4. Run the proposed command to create a link.
|
||||
# 5. To verify, run "munin-node-configure", you should notice the "nut_" record
|
||||
#
|
||||
# Plugin | Used | Suggestions
|
||||
# ------ | ---- | -----------
|
||||
# nut_ | yes | apc_AT_localhost
|
||||
#
|
||||
# 6. Restart munin: "/etc/init.d/munin-node restart"
|
||||
# 7. Hold on for 5 minutes at most and watch the graph appear.
|
||||
# 8. Customize voltage warning that are commented out for now.
|
||||
#
|
||||
#%# family=contrib
|
||||
#%# capabilities=autoconf suggest
|
||||
|
||||
function FETCH_DATA() {
|
||||
# UPS address, fetched from file name
|
||||
UPS=$(basename $0 | sed 's|^nut_||g' | sed 's|_AT_|@|g')
|
||||
|
||||
# Save data into variables
|
||||
model=$(upsc $UPS | grep ups.model: | cut -d" " -f2)
|
||||
in=$(upsc $UPS | grep input.voltage: | cut -d" " -f2)
|
||||
out=$(upsc $UPS | grep output.voltage: | cut -d" " -f2)
|
||||
load=$(upsc $UPS | grep ups.load: | cut -d" " -f2)
|
||||
charge=$(upsc $UPS | grep battery.charge: | cut -d" " -f2)
|
||||
}
|
||||
|
||||
# Munin routines
|
||||
case "$1" in
|
||||
autoconf)
|
||||
grep ^MONITOR < /etc/nut/upsmon.conf &> /dev/null
|
||||
if [[ "$?" = "0" ]]; then
|
||||
echo yes
|
||||
exit 0
|
||||
else
|
||||
echo "no (NUT not installed or no UPS info available in /etc/nut/upsmon.conf)"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
config)
|
||||
FETCH_DATA
|
||||
cat << EOM
|
||||
graph_title UPS: $model - $UPS
|
||||
graph_category sensors
|
||||
graph_info The graph shows UPS info monitored by NUT.
|
||||
graph_args --base 1000 --lower-limit 0
|
||||
in.label Input Voltage (v)
|
||||
in.warning 190:260
|
||||
out.label Output Voltage (v)
|
||||
out.critical 208:253
|
||||
charge.label Battery Charge (%)
|
||||
charge.draw AREA
|
||||
charge.colour 00aaaa
|
||||
charge.warning 30:
|
||||
load.label UPS Load (%)
|
||||
load.colour ff0000
|
||||
load.warning :80
|
||||
EOM
|
||||
exit 0
|
||||
;;
|
||||
suggest)
|
||||
grep ^MONITOR < /etc/nut/upsmon.conf | cut -d" " -f2 | sed 's|@|_AT_|g'
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
|
||||
FETCH_DATA
|
||||
# Print data for Munin
|
||||
cat << EOM
|
||||
in.value $in
|
||||
out.value $out
|
||||
charge.value $charge
|
||||
load.value $load
|
||||
EOM
|
||||
exit 0
|
||||
;;
|
||||
esac
|
318
plugins/power/nutups2_
Executable file
318
plugins/power/nutups2_
Executable file
|
@ -0,0 +1,318 @@
|
|||
#! /usr/bin/perl -w
|
||||
|
||||
=head1 NAME
|
||||
|
||||
nutups2_ - Plugin to monitor UPSes managed by NUT
|
||||
|
||||
=head1 CONFIGURATION
|
||||
|
||||
Generally none needed.
|
||||
|
||||
If you have installed NUT at a non-standard location, then you can specify its
|
||||
location like:
|
||||
|
||||
[nutups2_*]
|
||||
env.upsc /some/location/bin/upsc
|
||||
|
||||
=head1 WARNING AND CRITICAL SETTINGS
|
||||
|
||||
If upsc reports 'high' and 'low' values for some attribute, those will used
|
||||
as the critical range. Otherwise the following environment variables can be
|
||||
used to set the defaults for all fields:
|
||||
|
||||
env.warning
|
||||
env.critical
|
||||
|
||||
You can also control individual fields like:
|
||||
|
||||
env.input_L1.warning
|
||||
env.output.critical
|
||||
|
||||
=head1 MAGIC MARKERS
|
||||
|
||||
#%# family=auto
|
||||
#%# capabilities=autoconf suggest
|
||||
|
||||
=head1 FEATURES
|
||||
|
||||
The plugin supports reporting battery charge, UPS load, input/output
|
||||
frequencies/currents/voltages, apparent and real power output, humidity and
|
||||
temperature readings. Note however that different UPS models report different
|
||||
levels of detail; the plugin reports whatever information the NUT UPS driver
|
||||
(and in turn the UPS itself) provides.
|
||||
|
||||
Although the 'suggest' command will only offer UPSes for which the local host
|
||||
is the master, you can also monitor remote UPSes if you include the host name
|
||||
in the symlink, like:
|
||||
|
||||
nutups2_<upsname>@<hostname or address>_frequency
|
||||
|
||||
etc.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Gábor Gombás <gombasg@sztaki.hu>
|
||||
|
||||
=head1 LICENSE
|
||||
|
||||
GPLv2 or later
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use Munin::Plugin;
|
||||
use Carp;
|
||||
|
||||
my $UPSC = $ENV{'upsc'} || 'upsc';
|
||||
|
||||
# For the 'filter' field, the first sub-match should contain the name to
|
||||
# display, and the second sub-match should indicate if it is a nominal
|
||||
# value instead of a sensor reading.
|
||||
my %config = (
|
||||
charge => {
|
||||
filter => qr/^(.*)\.(?:charge|load)$/,
|
||||
title => 'UPS load and battery charge',
|
||||
args => '--base 1000 -l 0 -u 100',
|
||||
vlabel => '%',
|
||||
config => \&common_config,
|
||||
fetch => \&common_fetch,
|
||||
},
|
||||
current => {
|
||||
filter => qr/^(.*)\.current(\.nominal)?$/,
|
||||
title => 'UPS current',
|
||||
args => '--base 1000 -l 0',
|
||||
vlabel => 'Amper',
|
||||
config => \&common_config,
|
||||
fetch => \&common_fetch,
|
||||
},
|
||||
frequency => {
|
||||
filter => qr/^(.*)\.frequency(\.nominal)?$/,
|
||||
title => 'UPS frequency',
|
||||
args => '--base 1000 -l 0',
|
||||
vlabel => 'Hz',
|
||||
config => \&common_config,
|
||||
fetch => \&common_fetch,
|
||||
},
|
||||
humidity => {
|
||||
filter => qr/^(.*)\.humidity$/,
|
||||
title => 'UPS humidity',
|
||||
args => '--base 1000 -l 0',
|
||||
vlabel => '%',
|
||||
config => \&common_config,
|
||||
fetch => \&common_fetch,
|
||||
},
|
||||
power => {
|
||||
filter => qr/^(.*)\.power(\.nominal)?$/,
|
||||
title => 'UPS apparent power',
|
||||
args => '--base 1000 -l 0',
|
||||
vlabel => 'VA',
|
||||
config => \&common_config,
|
||||
fetch => \&common_fetch,
|
||||
},
|
||||
realpower => {
|
||||
filter => qr/^(.*)\.realpower(\.nominal)?$/,
|
||||
title => 'UPS real power',
|
||||
args => '--base 1000 -l 0',
|
||||
vlabel => 'Watt',
|
||||
config => \&common_config,
|
||||
fetch => \&common_fetch,
|
||||
},
|
||||
temperature => {
|
||||
filter => qr/^(.*)\.temperature$/,
|
||||
title => 'UPS temperature',
|
||||
args => '--base 1000 -l 0',
|
||||
vlabel => 'Celsius',
|
||||
config => \&common_config,
|
||||
fetch => \&common_fetch,
|
||||
},
|
||||
voltage => {
|
||||
filter => qr/^(.*)\.voltage(\.nominal)?$/,
|
||||
title => 'UPS voltage',
|
||||
args => '--base 1000 -l 0',
|
||||
vlabel => 'Volt',
|
||||
config => \&common_config,
|
||||
fetch => \&common_fetch,
|
||||
},
|
||||
);
|
||||
|
||||
sub read_ups_values {
|
||||
my $ups = shift;
|
||||
|
||||
my @lines = `$UPSC $ups 2>/dev/null`;
|
||||
my $values = {};
|
||||
for my $line (@lines) {
|
||||
chomp $line;
|
||||
|
||||
my ($key, $value) = $line =~ m/^([^:]+):\s+(\S.*)$/;
|
||||
$values->{$key} = $value;
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
sub graph_config {
|
||||
my ($func, $ups, $values) = @_;
|
||||
|
||||
print "graph_title " . $config{$func}->{'title'} . " ($ups)\n";
|
||||
print "graph_vlabel " . $config{$func}->{'vlabel'} . "\n";
|
||||
print "graph_args " . $config{$func}->{'args'} . "\n";
|
||||
print "graph_category sensors\n";
|
||||
|
||||
my @info;
|
||||
push @info, 'Manufacturer: "' . $values->{'ups.mfr'} . '"'
|
||||
if exists $values->{'ups.mfr'} and $values->{'ups.mfr'} ne 'unknown';
|
||||
push @info, 'Model: "' . $values->{'ups.model'} . '"'
|
||||
if exists $values->{'ups.model'};
|
||||
push @info, 'Serial: "' . $values->{'ups.serial'} . '"'
|
||||
if exists $values->{'ups.serial'};
|
||||
map { s/\s+/ /g } @info;
|
||||
print "graph_info " . join(', ', @info) . "\n"
|
||||
if @info;
|
||||
}
|
||||
|
||||
sub print_range_warning {
|
||||
my ($id, $key, $values) = @_;
|
||||
|
||||
if (exists $values->{$key . '.minimum'}) {
|
||||
print $id . ".min " . $values->{$key . '.minimum'} . "\n";
|
||||
}
|
||||
if (exists $values->{$key . '.maximum'}) {
|
||||
print $id . ".max " . $values->{$key . '.maximum'} . "\n";
|
||||
}
|
||||
|
||||
my $range = '';
|
||||
if (exists $values->{$key . '.high'}) {
|
||||
$range = $values->{$key . '.high'};
|
||||
}
|
||||
if (exists $values->{$key . '.low'}) {
|
||||
$range = $values->{$key . '.low'} . ':' . $range;
|
||||
}
|
||||
# print_thresholds() needs 'undef' for no range
|
||||
undef $range unless $range;
|
||||
print_thresholds($id, undef, undef, undef, $range);
|
||||
}
|
||||
|
||||
# Example keys for voltages:
|
||||
# battery.voltage
|
||||
# battery.voltage.minimum
|
||||
# battery.voltage.maximum
|
||||
# battery.voltage.nominal
|
||||
# input.voltage
|
||||
# input.voltage.minimum
|
||||
# input.voltage.maximum
|
||||
# input.bypass.L1-N.voltage
|
||||
# input.L1-N.voltage
|
||||
# output.voltage
|
||||
# output.voltage.nominal
|
||||
# output.L1-N.voltage
|
||||
#
|
||||
# Replace 'voltage' with 'current' in the above list to get an example
|
||||
# for current keys.
|
||||
#
|
||||
# Frequency keys:
|
||||
# input.frequency
|
||||
# input.frequency.nominal
|
||||
# input.bypass.frequency
|
||||
# input.bypass.frequency.nominal
|
||||
# output.frequency
|
||||
# output.frequency.nominal
|
||||
# output.frequency.minimum
|
||||
# output.frequency.maximum
|
||||
sub common_config {
|
||||
my ($func, $ups) = @_;
|
||||
|
||||
my $values = read_ups_values($ups);
|
||||
graph_config($func, $ups, $values);
|
||||
for my $key (sort keys %$values) {
|
||||
my ($field, $nominal) = $key =~ $config{$func}->{'filter'};
|
||||
next unless $field;
|
||||
|
||||
$field .= $nominal if $nominal;
|
||||
my $id = clean_fieldname($field);
|
||||
|
||||
# These labels look better this way and are still short enough
|
||||
$field = $key if $func =~ m/(charge|temperature|humidity)/;
|
||||
|
||||
# Beautification
|
||||
$field = ucfirst($field);
|
||||
$field =~ s/\./ /g;
|
||||
|
||||
print $id . ".label " . $field . "\n";
|
||||
print $id . ".type GAUGE\n";
|
||||
|
||||
# Draw nominal values a litle thinner
|
||||
print $id . ".draw LINE1\n" if $nominal;
|
||||
|
||||
print_range_warning($id, $key, $values);
|
||||
}
|
||||
}
|
||||
|
||||
sub common_fetch {
|
||||
my ($func, $ups) = @_;
|
||||
|
||||
my $values = read_ups_values($ups);
|
||||
for my $key (sort keys %$values) {
|
||||
my ($field, $nominal) = $key =~ $config{$func}->{'filter'};
|
||||
next unless $field;
|
||||
|
||||
$field .= $nominal if $nominal;
|
||||
my $id = clean_fieldname($field);
|
||||
|
||||
print $id . ".value " . $values->{$key} . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ($ARGV[0] and $ARGV[0] eq 'autoconf') {
|
||||
# The former nutups_ plugin parsed upsmon.conf. But for a large UPS
|
||||
# that powers dozens or hundreds of machines, that would mean
|
||||
# monitoring the same UPS from every host it powers, which does not
|
||||
# make sense. Using upsc and defaulting to localhost means that
|
||||
# 'autoconf' will only enable the plugin on the UPS master node, where
|
||||
# upsd is running.
|
||||
my @upses = `$UPSC -l 2>/dev/null`;
|
||||
if ($?) {
|
||||
if ($? == -1) {
|
||||
print "no (program '$UPSC' was not found)\n";
|
||||
}
|
||||
else {
|
||||
print "no (program '$UPSC -l' returned error)\n";
|
||||
}
|
||||
exit 0;
|
||||
}
|
||||
|
||||
map { chomp $_ } @upses;
|
||||
unless (@upses and $upses[0]) {
|
||||
print "no (program '$UPSC' listed no units)\n";
|
||||
}
|
||||
else {
|
||||
print "yes\n";
|
||||
}
|
||||
exit 0;
|
||||
}
|
||||
|
||||
if ($ARGV[0] and $ARGV[0] eq 'suggest') {
|
||||
my @upses = `$UPSC -l 2>/dev/null`;
|
||||
for my $ups (@upses) {
|
||||
chomp $ups;
|
||||
for my $metric (keys %config) {
|
||||
my $values = read_ups_values($ups);
|
||||
my @keys = grep { +$_ =~ $config{$metric}->{'filter'} } keys(%$values);
|
||||
print $ups . '_' . $metric . "\n" if @keys;
|
||||
}
|
||||
}
|
||||
exit 0;
|
||||
}
|
||||
|
||||
croak("Unknown command line arguments") if $ARGV[0] and $ARGV[0] ne 'config';
|
||||
|
||||
# The UPS name may contain underscores
|
||||
my $fn_re = join('|', keys %config);
|
||||
my ($ups, $func) = $0 =~ m/nutups2_(.*)_($fn_re)$/;
|
||||
|
||||
if ($ARGV[0] and $ARGV[0] eq 'config') {
|
||||
$config{$func}->{'config'}($func, $ups);
|
||||
}
|
||||
else {
|
||||
$config{$func}->{'fetch'}($func, $ups);
|
||||
}
|
||||
|
||||
exit 0;
|
533
plugins/power/snmp__apc_ups
Executable file
533
plugins/power/snmp__apc_ups
Executable file
|
@ -0,0 +1,533 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
=head1 NAME
|
||||
|
||||
snmp__apc_ups - Munin multigraph plugin for APC UPSes
|
||||
|
||||
=head1 APPLICABLE SYSTEMS
|
||||
|
||||
The UPS must support the PowerNet-MIB published by APC. This includes
|
||||
the APC Smart-UPS series on which this plugin was tested.
|
||||
|
||||
=head1 CONFIGURATION
|
||||
|
||||
As a rule SNMP plugins need site specific configuration. The default
|
||||
configuration (shown here) will only work on insecure sites/devices.
|
||||
|
||||
[snmp_*]
|
||||
env.version 2
|
||||
env.community public
|
||||
|
||||
In general SNMP is not very secure at all unless you use SNMP version
|
||||
3 which supports authentication and privacy (encryption). But in any
|
||||
case the community string for your devices should not be "public".
|
||||
|
||||
Please see 'perldoc Munin::Plugin::SNMP' for further configuration
|
||||
information.
|
||||
|
||||
=head1 INTERPRETATION
|
||||
|
||||
Please refer to the PowerNet-MIB when in doubt.
|
||||
|
||||
=head1 MIB INFORMATION
|
||||
|
||||
This plugin requires support for the PowerNet-MIB published by APC.
|
||||
|
||||
=head1 PROGRAMMERS
|
||||
|
||||
This plugin is actually a generic SNMP multigraph plugin. If you
|
||||
customize the data structures, especially %oidList and %label which is
|
||||
used to drive the loops. Take care that labels and structure of these
|
||||
hashes match otherwise things will disappear with not much warning.
|
||||
But se munin-node.log, munin-update.log and run the plugin with
|
||||
munin-run.
|
||||
|
||||
=head1 MAGIC MARKERS
|
||||
|
||||
#%# family=snmpauto
|
||||
#%# capabilities=snmpconf
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
Probably.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Based on work by Gorlow Maxim and Andrey Yakovlev. Totaly reworked by
|
||||
Nicolai Langfeldt, BroadNet AS, Oslo, Norway.
|
||||
|
||||
(C) 2013 BroadNet AS, Nicolai Langfeldt
|
||||
|
||||
=head1 LICENSE
|
||||
|
||||
GPLv2 only.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
USA.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use feature qw(say);
|
||||
|
||||
use Carp;
|
||||
use Data::Dumper;
|
||||
|
||||
use Munin::Plugin;
|
||||
use Munin::Plugin::SNMP;
|
||||
|
||||
use vars qw($DEBUG);
|
||||
|
||||
$DEBUG = $Munin::Plugin::DEBUG;
|
||||
|
||||
# ################ Change here to customize
|
||||
|
||||
# oidList - things to graph - must be complete
|
||||
|
||||
my %oidList =
|
||||
# _meta will be fetched but not graphed. The values can be placed in
|
||||
# texts by [OID:1.3.6.....] notation in any text in the "config"
|
||||
# output from the plugin. _meta is not used anywhere else than for
|
||||
# this.
|
||||
( _meta =>
|
||||
{ upsBasicIdentModel => '1.3.6.1.4.1.318.1.1.1.1.1.1.0',
|
||||
upsAdvIdentSerialNumber => '1.3.6.1.4.1.318.1.1.1.1.2.3.0',
|
||||
upsAdvConfigRatedOutputVoltage => '1.3.6.1.4.1.318.1.1.1.5.2.1.0', # 230
|
||||
upsAdvConfigHighTransferVolt => '1.3.6.1.4.1.318.1.1.1.5.2.2.0', # 208
|
||||
upsAdvConfigLowTransferVolt => '1.3.6.1.4.1.318.1.1.1.5.2.3.0', # 253
|
||||
},
|
||||
time =>
|
||||
{ upsAdvBatteryRunTimeRemaining => '1.3.6.1.4.1.318.1.1.1.2.2.3.0',
|
||||
upsAdvConfigLowBatteryRunTime => '1.3.6.1.4.1.318.1.1.1.5.2.8.0' },
|
||||
volt =>
|
||||
{ upsAdvOutputVoltage => '1.3.6.1.4.1.318.1.1.1.4.2.1.0',
|
||||
upsAdvInputLineVoltage => '1.3.6.1.4.1.318.1.1.1.3.2.1.0',
|
||||
upsAdvInputMaxLineVoltage => '1.3.6.1.4.1.318.1.1.1.3.2.2.0',
|
||||
upsAdvInputMinLineVoltage => '1.3.6.1.4.1.318.1.1.1.3.2.3.0' },
|
||||
batteryvolt =>
|
||||
{ upsAdvBatteryActualVoltage => '1.3.6.1.4.1.318.1.1.1.2.2.8.0' },
|
||||
frequency =>
|
||||
{ upsAdvOutputFrequency => '1.3.6.1.4.1.318.1.1.1.4.2.2.0',
|
||||
upsAdvInputFrequency => '1.3.6.1.4.1.318.1.1.1.3.2.4.0' },
|
||||
status =>
|
||||
{ upsBasicOutputStatus => '1.3.6.1.4.1.318.1.1.1.4.1.1.0',
|
||||
upsBasicBatteryStatus => '1.3.6.1.4.1.318.1.1.1.2.1.1.0',
|
||||
upsAdvBatteryReplaceIndicator => '1.3.6.1.4.1.318.1.1.1.2.2.4.0',
|
||||
upsCommStatus => '1.3.6.1.4.1.318.1.1.1.8.1.0',
|
||||
upsAdvTestDiagnosticsResults => '1.3.6.1.4.1.318.1.1.1.7.2.3.0' },
|
||||
temperature =>
|
||||
{ upsAdvBatteryTemperature => '1.3.6.1.4.1.318.1.1.1.2.2.2.0',
|
||||
iemStatusProbeCurrentTemp => '1.3.6.1.4.1.318.1.1.10.2.3.2.1.4.1' },
|
||||
load =>
|
||||
{ upsAdvOutputLoad => '1.3.6.1.4.1.318.1.1.1.4.2.3.0',
|
||||
upsAdvBatteryCapacity => '1.3.6.1.4.1.318.1.1.1.2.2.1.0' },
|
||||
current =>
|
||||
{ upsAdvOutputCurrent => '1.3.6.1.4.1.318.1.1.1.4.2.4.0',
|
||||
upsAdvBatteryCurrent => '1.3.6.1.4.1.318.1.1.1.2.2.9.0',
|
||||
upsAdvTotalDCCurrent => '1.3.6.1.4.1.318.1.1.1.2.2.10.0' },
|
||||
);
|
||||
|
||||
# Customize data series labels here. Must be complete otherwise the
|
||||
# data series will not appear in graphs.
|
||||
|
||||
my %label =
|
||||
( time => { upsAdvBatteryRunTimeRemaining => 'Time left',
|
||||
upsAdvConfigLowBatteryRunTime => 'Alarm' },
|
||||
volt => { upsAdvOutputVoltage => 'Output',
|
||||
upsAdvInputLineVoltage => 'Input',
|
||||
upsAdvInputMaxLineVoltage => 'Max In',
|
||||
upsAdvInputMinLineVoltage => 'Min In' },
|
||||
batteryvolt => { upsAdvBatteryActualVoltage => 'Battery' },
|
||||
frequency => { upsAdvOutputFrequency => 'Output',
|
||||
upsAdvInputFrequency => 'Input' },
|
||||
status => { upsBasicOutputStatus => 'Output',
|
||||
upsBasicBatteryStatus => 'Battery',
|
||||
upsCommStatus => 'Comms',
|
||||
upsAdvTestDiagnosticsResults => 'Diag',
|
||||
upsAdvBatteryReplaceIndicator => 'Replace' },
|
||||
temperature => { upsAdvBatteryTemperature => 'Battery',
|
||||
iemStatusProbeCurrentTemp => 'Probe' },
|
||||
load => { upsAdvOutputLoad => 'Usage',
|
||||
upsAdvBatteryCapacity => 'Total' },
|
||||
current => { upsAdvOutputCurrent => 'Output',
|
||||
upsAdvBatteryCurrent => 'Battery',
|
||||
upsAdvTotalDCCurrent => 'Total DC' }
|
||||
);
|
||||
|
||||
|
||||
# http://munin-monitoring.org/wiki/fieldname.type for more
|
||||
# information. Overrides here:
|
||||
|
||||
# Default
|
||||
my $tstype = 'GAUGE';
|
||||
|
||||
# Overrides
|
||||
my %tstype = ();
|
||||
|
||||
# How to draw.
|
||||
#
|
||||
# By default drawing is LINE1, overrides here. It will be hard to do
|
||||
# the STACK types in this plugin since they are ordering sensitive.
|
||||
# If you want that you will need to expand this plugin to define and
|
||||
# use a %ordering hash that enforces field order so that stacks come
|
||||
# out right.
|
||||
|
||||
my %tsdraw =
|
||||
(
|
||||
batteryvolt => { upsAdvBatteryActualVoltage => 'LINE2' },
|
||||
);
|
||||
|
||||
# Minimum and maximum values. Values outside the ragne given by these
|
||||
# will be tossed. None needed by default, add as needed in the same
|
||||
# nested fashion as %label.
|
||||
|
||||
my %tsmin = ();
|
||||
|
||||
my %tsmax = ();
|
||||
|
||||
# Example:
|
||||
#
|
||||
# my %tsmin =
|
||||
# ( temperature => { upsAdvBatteryTemperature => 10 } );
|
||||
#
|
||||
# my %tsmax =
|
||||
# ( temperature => { upsAdvBatteryTemperature => 150 } );
|
||||
|
||||
# Warning and Critical ranges. None needed by default. Add as
|
||||
# needed.
|
||||
|
||||
my %tswarn =
|
||||
( status => { upsBasicOutputStatus => '2:5' },
|
||||
time => { upsAdvBatteryRunTimeRemaining => '90:' },
|
||||
);
|
||||
|
||||
|
||||
my %tscrit =
|
||||
( status => { upsAdvBatteryReplaceIndicator => '1:1',
|
||||
upsBasicBatteryStatus => '2:2',
|
||||
upsBasicOutputStatus => '2:6',
|
||||
upsCommStatus => '1:1',
|
||||
upsAdvTestDiagnosticsResults => '1:1' },
|
||||
|
||||
frequency => { upsAdvInputFrequency => '49:51',
|
||||
upsAdvOutputFrequency => '49:51' },
|
||||
|
||||
time => { upsAdvBatteryRunTimeRemaining => '60:' },
|
||||
|
||||
volt => { upsAdvOutputVoltage =>
|
||||
'[OID:1.3.6.1.4.1.318.1.1.1.5.2.3.0]:'.
|
||||
'[OID:1.3.6.1.4.1.318.1.1.1.5.2.2.0]',
|
||||
upsAdvInputLineVoltage =>
|
||||
'[OID:1.3.6.1.4.1.318.1.1.1.5.2.3.0]:'.
|
||||
'[OID:1.3.6.1.4.1.318.1.1.1.5.2.2.0]' },
|
||||
);
|
||||
|
||||
my %cdef =
|
||||
( time =>
|
||||
{ upsAdvBatteryRunTimeRemaining => 'upsAdvBatteryRunTimeRemaining,6000,/',
|
||||
upsAdvConfigLowBatteryRunTime => 'upsAdvConfigLowBatteryRunTime,6000,/' }
|
||||
);
|
||||
|
||||
|
||||
my %title =
|
||||
( time => 'Time left on battery',
|
||||
volt => 'Line Voltages',
|
||||
batteryvolt => 'Battery Voltage',
|
||||
frequency => 'Line frequency',
|
||||
status => 'Status codes',
|
||||
temperature => 'Temperatures',
|
||||
load => 'Load/Capacity',
|
||||
current => 'Currents'
|
||||
);
|
||||
|
||||
# Vertical labels on the graph
|
||||
|
||||
my %vlabel =
|
||||
( time => 'minutes',
|
||||
volt => 'Volt',
|
||||
batteryvolt => 'Volt',
|
||||
frequency => 'Hz',
|
||||
status => 'code value',
|
||||
temperature => 'Celsius',
|
||||
load => 'Percent',
|
||||
current => 'Ampere',
|
||||
);
|
||||
|
||||
# Extra information on the whole graph.
|
||||
|
||||
my %info =
|
||||
( time => 'Time left on battery and when shutdown occurs. In minutes.',
|
||||
volt => 'Current input and output voltages. The min and max '.
|
||||
'readings are for the last minute. Note that the values '.
|
||||
'are collected every 5 minutes. Nominal voltage is '.
|
||||
'[OID:1.3.6.1.4.1.318.1.1.1.5.2.1.0]',
|
||||
status => 'Coded statuses. UPS Model: '.
|
||||
'[OID:1.3.6.1.4.1.318.1.1.1.1.1.1.0]. '.
|
||||
'Serial number: [OID:1.3.6.1.4.1.318.1.1.1.1.2.3.0]',
|
||||
load => 'Current load and capacity on/of the UPS in percent.',
|
||||
current => 'The current in amperes.',
|
||||
temperature => 'Current temperatures. Possebly only the battery.',
|
||||
batteryvolt => 'Current battery bus DC voltage. For a 24V battery pack '.
|
||||
'this should be around 26-27V.',
|
||||
frequency => 'Current input and output AC frequency',
|
||||
);
|
||||
|
||||
# Extra information for a time series
|
||||
|
||||
my %subinfo =
|
||||
( load =>
|
||||
{ upsAdvOutputLoad => 'The current UPS load expressed in percent '.
|
||||
'of rated capacity.',
|
||||
upsAdvBatteryCapacity => 'The remaining battery capacity expressed '.
|
||||
'in percent of full capacity.' },
|
||||
status =>
|
||||
{ upsBasicOutputStatus => 'Codes: 1: unknown, 2: onLine (GREEN), '.
|
||||
'3: onBattery (YELLOW) 4: onSmartBoost 5: timedSleeping, '.
|
||||
'6: softwareBypass 7: off 8: rebooting, '.
|
||||
'9: switchedBypass 10: hardwareFailureBypass, '.
|
||||
'11: sleepingUntilPowerReturn 12: onSmartTrim '.
|
||||
'13: ecoMode 14: hotStandby 15: onBatteryTest',
|
||||
|
||||
upsBasicBatteryStatus => 'The status of the UPS batteries. A '.
|
||||
'batteryLow(3) value indicates the UPS will be unable '.
|
||||
'to sustain the current load, and its services will be '.
|
||||
'lost if power is not restored. The amount of run time '.
|
||||
'in reserve at the time of low battery can be configured '.
|
||||
'by the upsAdvConfigLowBatteryRunTime.',
|
||||
|
||||
upsAdvBatteryReplaceIndicator => 'Battery replacement indicator. '.
|
||||
'1: All OK 2: Battery needs replacing',
|
||||
|
||||
upsCommStatus => "The status of agent's communication ".
|
||||
'with UPS. 1: OK 2: Failed',
|
||||
|
||||
upsAdvTestDiagnosticsResults => 'The results of the last UPS '.
|
||||
'diagnostics test performed. 1: OK, 2: Failed, '.
|
||||
'3: invalidTest, 4: testInProgress' },
|
||||
|
||||
time =>
|
||||
{ upsAdvBatteryRunTimeRemaining => 'The UPS battery run time '.
|
||||
'remaining before battery exhaustion.',
|
||||
upsAdvConfigLowBatteryRunTime => 'The desired run time of the UPS, '.
|
||||
'in minutes, once the low battery condition is reached. '.
|
||||
'During this time the UPS will produce a constant warning '.
|
||||
'tone which can not be disabled.' },
|
||||
current =>
|
||||
{ upsAdvOutputCurrent => "The current in Amperes drawn by the load on the UPS.",
|
||||
upsAdvBatteryCurrent => "The battery current in Apmeres.",
|
||||
upsAdvTotalDCCurrent => "The total DC current in Amperes.", },
|
||||
);
|
||||
|
||||
# Extinfo is presented in conjunction with the time series information
|
||||
# under the graph. Usually it supplies extra information specific to
|
||||
# a fault, but it might also provide any information for any reason.
|
||||
|
||||
my %extinfo =
|
||||
( status =>
|
||||
{ upsAdvTestDiagnosticsResults => "Last diagnostic performed [OID:1.3.6.1.4.1.318.1.1.1.7.2.4.0]" } );
|
||||
|
||||
# ########################## Code here
|
||||
|
||||
sub collect_snmp {
|
||||
# Mash together all the OIDs needed by the different graphs and
|
||||
# make a (one) query to get them all. Returns a hash of the
|
||||
# values keyed by OID.
|
||||
#
|
||||
# Occurrences of "noSuchInstance" is replaced by "U".
|
||||
|
||||
my ( $snmp ) = @_;
|
||||
|
||||
my @oids = ();
|
||||
|
||||
foreach my $graph ( keys %oidList ) {
|
||||
foreach my $oid ( values %{ $oidList{$graph} } ) {
|
||||
push(@oids, $oid);
|
||||
}
|
||||
}
|
||||
|
||||
my $values = $snmp->get_request( -varbindlist => \@oids );
|
||||
|
||||
if ( $snmp->error() ) {
|
||||
die "$Munin::Plugin::me: SNMP error ".$snmp->error();
|
||||
}
|
||||
|
||||
# Modify $values in place
|
||||
map { $values->{$_} = 'U'
|
||||
if $values->{$_} eq 'noSuchInstance'; } keys %$values;
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
|
||||
sub emit_a_fetch {
|
||||
# Emit just one value line
|
||||
my ( $text, $values, $key, $default ) = @_;
|
||||
|
||||
my $value = $values->{$key};
|
||||
$value = $default if ! defined $value;
|
||||
$value = 'U' if ! defined $value;
|
||||
|
||||
say "$text $value";
|
||||
}
|
||||
|
||||
|
||||
sub emit_fetch {
|
||||
# Spew out
|
||||
my ( $graph, $oids, $values ) = @_;
|
||||
|
||||
foreach my $label (keys %$oids) {
|
||||
emit_a_fetch( "$label.value", $values, $oids->{$label}, 'U' );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub emit_fetches {
|
||||
# Emit all the fetches for all the multigraphs
|
||||
my ( $snmp, $oids ) = @_;
|
||||
|
||||
my $values = collect_snmp( $snmp, $oids );
|
||||
|
||||
foreach my $graph (keys %label) {
|
||||
say "multigraph $graph";
|
||||
emit_fetch ( $graph, $oids->{$graph}, $values );
|
||||
say '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub replace_oid {
|
||||
my ( $str, $values ) = @_;
|
||||
|
||||
# If "str is [OID:1.3.6.1.2.1.1.5.0] then return the contents of sysName.0
|
||||
|
||||
my $oid = substr( $str, 5, -1 );
|
||||
$str = $values->{$oid};
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
|
||||
sub process_oids {
|
||||
my ( $str, $values ) = @_;
|
||||
|
||||
if ( ! defined $values ) {
|
||||
croak("no values");
|
||||
}
|
||||
|
||||
if ( $str =~ m/OID:/ ) {
|
||||
$str =~ s/(\[OID:[^]]*])/&replace_oid($1, $values)/eg;
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
|
||||
sub emit_a_config {
|
||||
# Emit a config line
|
||||
# IF there is a default, always emit line.
|
||||
# IF there is no default, only emit line if the hash lookup
|
||||
# exists.
|
||||
my ( $values, $text, $hash, $graph, $label, $default ) = @_;
|
||||
|
||||
if ( defined $default ) {
|
||||
my $value = $hash->{$graph}->{$label};
|
||||
$value = $default if ! defined $value;
|
||||
$value = 'U' if ! defined $value;
|
||||
|
||||
say process_oids( "$text $value", $values );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( exists $hash->{$graph}->{$label} ) {
|
||||
say process_oids( "$text " . $hash->{$graph}->{$label}, $values );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub emit_config {
|
||||
# Emit a graph configuration
|
||||
my ( $graph, $values ) = @_;
|
||||
|
||||
say "graph_title ".( $title{$graph} || "Untitled /$graph/");
|
||||
say process_oids( "graph_vlabel " . $vlabel{$graph}, $values );
|
||||
say "graph_category sensors";
|
||||
say process_oids( "graph_info " . $info{$graph}, $values );
|
||||
|
||||
foreach my $label (keys %{ $label{$graph} } ) {
|
||||
emit_a_config( $values, "$label.label", \%label, $graph, $label,
|
||||
$label );
|
||||
emit_a_config( $values, "$label.draw", \%tsdraw, $graph, $label,
|
||||
'LINE1' );
|
||||
emit_a_config( $values, "$label.type", \%tstype, $graph, $label,
|
||||
$tstype );
|
||||
emit_a_config( $values, "$label.min", \%tsmin, $graph, $label );
|
||||
emit_a_config( $values, "$label.max", \%tsmax, $graph, $label );
|
||||
emit_a_config( $values, "$label.cdef", \%cdef, $graph, $label );
|
||||
emit_a_config( $values, "$label.info", \%subinfo,$graph, $label );
|
||||
|
||||
emit_a_config( $values, "$label.warning", \%tswarn, $graph, $label );
|
||||
emit_a_config( $values, "$label.critical", \%tscrit, $graph, $label );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub emit_configs {
|
||||
my ( $snmp, $oids, $host, $results ) = @_;
|
||||
|
||||
my $values = collect_snmp( $snmp, $oids );
|
||||
|
||||
say "host_name $host";
|
||||
say "";
|
||||
|
||||
foreach my $graph (keys %label) {
|
||||
say "multigraph $graph";
|
||||
emit_config( $graph, $values );
|
||||
|
||||
# If dirty config allowed:
|
||||
emit_fetch ( $graph, $oids->{$graph}, $values );
|
||||
|
||||
say '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub main {
|
||||
# need_multigraph();
|
||||
|
||||
if ($ARGV[0] and $ARGV[0] eq 'snmpconf') {
|
||||
say "require 1.3.6.1.4.1.318.1.1.1.2.2.8.0 [0-9]";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
my ( $host, undef ) = Munin::Plugin::SNMP::config_session();
|
||||
|
||||
# Ensure that we get times in ticks (hundredths of a second)
|
||||
my $session =
|
||||
Munin::Plugin::SNMP->session( -translate => [ -timeticks => 0x0 ] );
|
||||
|
||||
|
||||
if ($ARGV[0] and $ARGV[0] eq 'config') {
|
||||
emit_configs( $session, \%oidList, $host );
|
||||
exit 0;
|
||||
}
|
||||
|
||||
emit_fetches( $session, \%oidList );
|
||||
exit 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
main();
|
445
plugins/power/snmp__ipoman_
Executable file
445
plugins/power/snmp__ipoman_
Executable file
|
@ -0,0 +1,445 @@
|
|||
#!/usr/bin/perl -w
|
||||
#
|
||||
# What is snmp__ipoman_
|
||||
# ----------------------
|
||||
# snmp__ipoman is a munin plugin written for the Ingrasys IpomanII 1202
|
||||
# Power Distribution Unit. It should work on any PDU conforming to
|
||||
# the IPOMANII-MIB.
|
||||
#
|
||||
# How do I use it
|
||||
# ---------------
|
||||
# You can use this plugin on a system with a working munin-node. Here's
|
||||
# how:
|
||||
#
|
||||
# 1. Copy snmp__ipoman_ to the directory where all your munin plugins
|
||||
# reside, for example /usr/share/munin/plugins.
|
||||
#
|
||||
# 2. Make the following symlinks to snmp__ipoman_ in that same directory
|
||||
#
|
||||
# snmp__ipoman_inletcurrent_
|
||||
# snmp__ipoman_inletpower_
|
||||
# snmp__ipoman_inletvoltage_
|
||||
# snmp__ipoman_outletpower_
|
||||
# snmp__ipoman_outletcurrent_
|
||||
#
|
||||
# (If you wonder why. I did not manage to make a plugin which has both
|
||||
# the 'snmpconf' and the 'suggest' capabilities. So either I had to make
|
||||
# separate plugins for all graph types, or I would have to make
|
||||
# assumptions on the number of ports and the address of the ipoman in
|
||||
# the script.)
|
||||
#
|
||||
# 3. Change to the directory where the links to munin plugins reside
|
||||
# that are to be run by munin-node, for example /etc/munin/plugins/
|
||||
#
|
||||
# 4. Run munin-node-configure-snmp:
|
||||
#
|
||||
# $ munin-node-configure-snmp --snmpversion=1 <hostname> | sh -x
|
||||
#
|
||||
# where <hostname> is the hostname or ip address of your ipoman. This
|
||||
# will create and print a bunch of symlinks to snmp__ipoman_ which will
|
||||
# output current and power usage for all available outlets of the
|
||||
# ipoman, and current, power usage and voltage/frequency on all inlets
|
||||
# of the ipoman.
|
||||
#
|
||||
# 5. Restart munin-node
|
||||
#
|
||||
# 6. Make an entry in your munin server's munin.conf:
|
||||
#
|
||||
# [<hostname of ipoman as entered in 4.>]
|
||||
# address <address of munin-node>
|
||||
# use_node_name no
|
||||
#
|
||||
# 7. Done.
|
||||
#
|
||||
# Copyright (C) 2009 Rien Broekstra <rien@rename-it.nl>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; version 2 dated June,
|
||||
# 1991.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# Munin plugin to monitor power consumption and current of the sockets of an
|
||||
# Ingrasys IpomanII 1202 Power Distribution Unit, or any power distribution
|
||||
# unit that conforms to IPOMANII-MIB via SNMP.
|
||||
#
|
||||
# Parameters:
|
||||
#
|
||||
# config
|
||||
# snmpconf
|
||||
#
|
||||
# Relevant OID's under .iso.org.dod.internet.private.enterprises.ingrasys.product.pduAgent.iPoManII
|
||||
# .ipmObjects.ipmDevice.ipmDeviceOutlet.ipmDeviceOutletNumber.0
|
||||
# .ipmObjects.ipmDevice.ipmDeviceOutlet.ipmDeviceOutletStatusTable.ipmDeviceOutletStatusEntry.outletStatusIndex.1
|
||||
# .ipmObjects.ipmDevice.ipmDeviceOutlet.ipmDeviceOutletStatusTable.ipmDeviceOutletStatusEntry.outletStatusCurrent.1
|
||||
# .ipmObjects.ipmDevice.ipmDeviceOutlet.ipmDeviceOutletStatusTable.ipmDeviceOutletStatusEntry.outletStatusKwatt.1
|
||||
# .ipmObjects.ipmDevice.ipmDeviceOutlet.ipmDeviceOutletStatusTable.ipmDeviceOutletStatusEntry.outletStatusWH.1
|
||||
#
|
||||
# Version 0.1, Aug 4, 2009
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# MAGIC MARKERS:
|
||||
#
|
||||
#%# family=snmpauto
|
||||
#%# capabilities=snmpconf
|
||||
|
||||
use strict;
|
||||
use Net::SNMP;
|
||||
|
||||
my $DEBUG = 0;
|
||||
|
||||
my $host = $ENV{host} || undef;
|
||||
my $port = $ENV{port} || 161;
|
||||
my $community = $ENV{community} || "public";
|
||||
my $iface = $ENV{interface} || undef;
|
||||
|
||||
my $socketnumber;
|
||||
my $response;
|
||||
my $graphtype;
|
||||
|
||||
#
|
||||
# Infer host, inlet/socketnumber and graphtype from the symlink name to this plugin.
|
||||
#
|
||||
if ($0 =~ /^(?:|.*\/)snmp_([^_]*)_ipoman_([^_]*)_(.*)$/)
|
||||
{
|
||||
$host = $1;
|
||||
$graphtype = $2;
|
||||
$socketnumber = $3;
|
||||
if ($host =~ /^([^:]+):(\d+)$/) {
|
||||
$host = $1;
|
||||
$port = $2;
|
||||
}
|
||||
}
|
||||
|
||||
if (!defined($graphtype)) {
|
||||
die "# Error: couldn't understand what quantity I'm supposed to monitor.";
|
||||
}
|
||||
|
||||
#
|
||||
# The relevant OID's on the IPOMAN
|
||||
#
|
||||
my $oid_inletnumber = ".1.3.6.1.4.1.2468.1.4.2.1.3.1.1.0";
|
||||
my $oid_inletindextable = ".1.3.6.1.4.1.2468.1.4.2.1.3.1.2.1.1.";
|
||||
my $oid_inletvoltage = ".1.3.6.1.4.1.2468.1.4.2.1.3.1.3.1.2.";
|
||||
my $oid_inletcurrent = ".1.3.6.1.4.1.2468.1.4.2.1.3.1.3.1.3.";
|
||||
my $oid_inletfrequency = ".1.3.6.1.4.1.2468.1.4.2.1.3.1.3.1.4.";
|
||||
my $oid_inletenergy = ".1.3.6.1.4.1.2468.1.4.2.1.3.1.3.1.5.";
|
||||
|
||||
my $oid_outletnumber = ".1.3.6.1.4.1.2468.1.4.2.1.3.2.1.0";
|
||||
my $oid_outletindextable = ".1.3.6.1.4.1.2468.1.4.2.1.3.2.3.1.1.";
|
||||
my $oid_outletdescription = ".1.3.6.1.4.1.2468.1.4.2.1.3.2.2.1.2.";
|
||||
my $oid_outletcurrent = ".1.3.6.1.4.1.2468.1.4.2.1.3.2.3.1.3.";
|
||||
my $oid_outletenergy = ".1.3.6.1.4.1.2468.1.4.2.1.3.2.3.1.4.";
|
||||
# FIXME: The voltage is not defined per outlet. For now we just assume that all sockets have the voltage on inlet 1.
|
||||
my $oid_outletvoltage = ".1.3.6.1.4.1.2468.1.4.2.1.3.1.3.1.2.1";
|
||||
|
||||
#
|
||||
# The snmpconf section prints out what oid's we need for the quantity we want to monitor, and where we find out how many ports the device has.
|
||||
#
|
||||
if (defined $ARGV[0] and $ARGV[0] eq "snmpconf") {
|
||||
if ($graphtype eq "inletvoltage") {
|
||||
print "number $oid_inletnumber\n";
|
||||
print "index $oid_inletindextable\n";
|
||||
print "require $oid_inletvoltage [0-9]+\n";
|
||||
print "require $oid_inletfrequency [0-9]+\n";
|
||||
}
|
||||
elsif ($graphtype eq "inletcurrent") {
|
||||
print "number $oid_inletnumber\n";
|
||||
print "index $oid_inletindextable\n";
|
||||
print "require $oid_inletcurrent [0-9]+\n";
|
||||
}
|
||||
elsif ($graphtype eq "inletpower") {
|
||||
print "number $oid_inletnumber\n";
|
||||
print "index $oid_inletindextable\n";
|
||||
print "require $oid_inletvoltage [0-9]+\n";
|
||||
print "require $oid_inletcurrent [0-9]+\n";
|
||||
}
|
||||
elsif ($graphtype eq "outletcurrent") {
|
||||
print "number $oid_outletnumber\n";
|
||||
print "index $oid_outletindextable\n";
|
||||
print "require $oid_outletcurrent [0-9]+\n";
|
||||
}
|
||||
elsif ($graphtype eq "outletpower") {
|
||||
print "number $oid_outletnumber\n";
|
||||
print "index $oid_outletindextable\n";
|
||||
print "require $oid_outletvoltage [0-9]+\n";
|
||||
print "require $oid_outletcurrent [0-9]+\n";
|
||||
}
|
||||
else {
|
||||
print "require dont.graph.anything [0-9]+\n"
|
||||
}
|
||||
exit 0;
|
||||
}
|
||||
|
||||
#
|
||||
# For all other options we need to connect to the host in our $0. if we cannot, bail out.
|
||||
#
|
||||
if (!defined($host))
|
||||
{
|
||||
print "# Debug: $0 -- $1 -- $2\n" if $DEBUG;
|
||||
die "# Error: couldn't understand what I'm supposed to monitor.";
|
||||
}
|
||||
|
||||
my ($session, $error) = Net::SNMP->session(
|
||||
-hostname => $host,
|
||||
-community => $community,
|
||||
-port => $port
|
||||
);
|
||||
|
||||
if (!defined ($session))
|
||||
{
|
||||
die "Croaking: $error";
|
||||
}
|
||||
|
||||
#
|
||||
# Output graph configuration depending on what quantity we want to plot
|
||||
#
|
||||
if (defined $ARGV[0] and $ARGV[0] eq "config") {
|
||||
print "host_name $host\n";
|
||||
if ($graphtype eq "inletvoltage") {
|
||||
|
||||
print "graph_title Inlet $socketnumber voltage/frequency\n";
|
||||
|
||||
print "graph_args --base 1000 -l 0\n";
|
||||
print "graph_category sensors\n";
|
||||
print "graph_info This graph shows the tension and frequency to inlet $socketnumber on the Power Distribution Unit\n";
|
||||
|
||||
print "voltage.label Tension (V)\n";
|
||||
print "voltage.draw LINE2\n";
|
||||
print "voltage.type GAUGE\n";
|
||||
|
||||
print "frequency.label Frequency (Hz)\n";
|
||||
print "frequency.draw LINE2\n";
|
||||
print "frequency.type GAUGE\n";
|
||||
|
||||
}
|
||||
elsif ($graphtype eq "inletcurrent") {
|
||||
print "graph_title Inlet $socketnumber current\n";
|
||||
|
||||
print "graph_args --base 1000 -l 0\n";
|
||||
print "graph_category sensors\n";
|
||||
print "graph_info This graph shows the delivered current to inlet $socketnumber on the Power Distribution Unit\n";
|
||||
|
||||
print "current.label Current (A)\n";
|
||||
print "current.draw AREA\n";
|
||||
print "current.type GAUGE\n";
|
||||
|
||||
}
|
||||
elsif ($graphtype eq "inletpower") {
|
||||
print "graph_title Inlet $socketnumber power\n";
|
||||
|
||||
print "graph_args --base 1000 -l 0\n";
|
||||
print "graph_category sensors\n";
|
||||
print "graph_info This graph shows the delivered apparent and real power to inlet $socketnumber of the Power Distribution Unit\n";
|
||||
|
||||
print "apparentpower.label Apparent power (kVA)\n";
|
||||
print "apparentpower.draw LINE3\n";
|
||||
print "apparentpower.type GAUGE\n";
|
||||
|
||||
print "realpower.label Real power (kW)\n";
|
||||
print "realpower.draw AREA\n";
|
||||
print "realpower.type COUNTER\n";
|
||||
|
||||
exit 0;
|
||||
}
|
||||
elsif ($graphtype eq "outletcurrent") {
|
||||
print "graph_title Outlet $socketnumber current\n";
|
||||
|
||||
print "graph_args --base 1000 -l 0\n";
|
||||
print "graph_category sensors\n";
|
||||
print "graph_info This graph shows the delivered current to outlet $socketnumber of the Power Distribution Unit\n";
|
||||
|
||||
print "current.label Delivered current (A)\n";
|
||||
print "current.draw AREA\n";
|
||||
print "current.type GAUGE\n";
|
||||
}
|
||||
elsif ($graphtype eq "outletpower") {
|
||||
print "graph_title Outlet $socketnumber power\n";
|
||||
|
||||
print "graph_args --base 1000 -l 0\n";
|
||||
print "graph_category sensors\n";
|
||||
print "graph_info This graph shows the delivered apparent and real power to outlet $socketnumber of the Power Distribution Unit\n";
|
||||
|
||||
print "apparentpower.label Apparent power (kVA)\n";
|
||||
print "apparentpower.draw LINE3\n";
|
||||
print "apparentpower.type GAUGE\n";
|
||||
|
||||
print "realpower.label Real power (kW)\n";
|
||||
print "realpower.draw AREA\n";
|
||||
print "realpower.type COUNTER\n";
|
||||
|
||||
exit 0;
|
||||
}
|
||||
exit 0;
|
||||
}
|
||||
|
||||
if ($graphtype eq "inletvoltage") {
|
||||
my ($voltage, $frequency);
|
||||
|
||||
if (defined ($response = $session->get_request($oid_inletvoltage.$socketnumber))) {
|
||||
$voltage = $response->{$oid_inletvoltage.$socketnumber};
|
||||
}
|
||||
else {
|
||||
$voltage = 'U';
|
||||
}
|
||||
|
||||
if (defined ($response = $session->get_request($oid_inletfrequency.$socketnumber))) {
|
||||
$frequency = $response->{$oid_inletfrequency.$socketnumber};
|
||||
}
|
||||
else {
|
||||
$frequency = 'U';
|
||||
}
|
||||
|
||||
# The IPOMAN returns tension in 0.1V units.
|
||||
# Convert to V
|
||||
if ($voltage ne 'U') {
|
||||
$voltage = $voltage/10;
|
||||
}
|
||||
|
||||
# The IPOMAN returns frequency in 0.1Hz units.
|
||||
# Convert to Hz
|
||||
if ($frequency ne 'U') {
|
||||
$frequency = $frequency/10;
|
||||
}
|
||||
|
||||
print "voltage.value ", $voltage, "\n";
|
||||
print "frequency.value ", $frequency, "\n";
|
||||
}
|
||||
elsif ($graphtype eq "inletcurrent") {
|
||||
my $current;
|
||||
|
||||
if (defined ($response = $session->get_request($oid_inletcurrent.$socketnumber))) {
|
||||
$current = $response->{$oid_inletcurrent.$socketnumber};
|
||||
}
|
||||
else {
|
||||
$current = 'U';
|
||||
}
|
||||
|
||||
# The IPOMAN returns power in mA.
|
||||
# Convert to A:
|
||||
#
|
||||
if ($current ne 'U') {
|
||||
$current = $current/1000;
|
||||
}
|
||||
|
||||
print "current.value ", $current, "\n";
|
||||
}
|
||||
elsif ($graphtype eq "inletpower") {
|
||||
my ($current, $energy, $voltage, $apparentpower);
|
||||
|
||||
if (defined ($response = $session->get_request($oid_inletcurrent.$socketnumber))) {
|
||||
$current = $response->{$oid_inletcurrent.$socketnumber};
|
||||
}
|
||||
else {
|
||||
$current = 'U';
|
||||
}
|
||||
|
||||
if (defined ($response = $session->get_request($oid_inletenergy.$socketnumber))) {
|
||||
$energy = $response->{$oid_inletenergy.$socketnumber};
|
||||
}
|
||||
else {
|
||||
$energy = 'U';
|
||||
}
|
||||
|
||||
if (defined ($response = $session->get_request($oid_inletvoltage.$socketnumber))) {
|
||||
$voltage = $response->{$oid_inletvoltage.$socketnumber};
|
||||
}
|
||||
else {
|
||||
$voltage = 'U';
|
||||
}
|
||||
|
||||
# Calculate results
|
||||
# Apparent power (VA)= Voltage (V)* Current(A).
|
||||
# IPOMAN delivers voltage in units of 0.1V. and current in units of mA:
|
||||
if ($current ne 'U' && $voltage ne 'U') {
|
||||
$apparentpower = ($current/1000)*($voltage/10);
|
||||
}
|
||||
|
||||
#
|
||||
# The IPOMAN returns consumed energy in Wh. We want it in J (= Ws), in order for munin to graph in W.
|
||||
#
|
||||
if ($energy ne 'U') {
|
||||
$energy = $energy*3600;
|
||||
}
|
||||
|
||||
print "realpower.value ", $energy, "\n";
|
||||
print "apparentpower.value ", $apparentpower, "\n";
|
||||
}
|
||||
elsif ($graphtype eq "outletcurrent") {
|
||||
my $current;
|
||||
|
||||
if (defined ($response = $session->get_request($oid_outletcurrent.$socketnumber))) {
|
||||
$current = $response->{$oid_outletcurrent.$socketnumber};
|
||||
}
|
||||
else {
|
||||
$current = 'U';
|
||||
}
|
||||
|
||||
# The IPOMAN returns power in mA.
|
||||
# Convert to A:
|
||||
#
|
||||
if ($current ne 'U') {
|
||||
$current = $current/1000;
|
||||
}
|
||||
|
||||
print "current.value ", $current, "\n";
|
||||
}
|
||||
elsif ($graphtype eq "outletpower") {
|
||||
my ($current, $energy, $voltage, $apparentpower);
|
||||
|
||||
if (defined ($response = $session->get_request($oid_outletcurrent.$socketnumber))) {
|
||||
$current = $response->{$oid_outletcurrent.$socketnumber};
|
||||
}
|
||||
else {
|
||||
$current = 'U';
|
||||
}
|
||||
|
||||
if (defined ($response = $session->get_request($oid_outletenergy.$socketnumber))) {
|
||||
$energy = $response->{$oid_outletenergy.$socketnumber};
|
||||
}
|
||||
else {
|
||||
$energy = 'U';
|
||||
}
|
||||
|
||||
if (defined ($response = $session->get_request($oid_outletvoltage))) {
|
||||
$voltage = $response->{$oid_outletvoltage};
|
||||
}
|
||||
else {
|
||||
$voltage = 'U';
|
||||
}
|
||||
|
||||
#
|
||||
# Calculate results
|
||||
# Apparent power (VA)= Voltage (V)* Current(A).
|
||||
# IPOMAN delivers voltage in units of 0.1V. and current in units of mA:
|
||||
if ($current ne 'U' && $voltage ne 'U') {
|
||||
$apparentpower = ($current/1000)*($voltage/10);
|
||||
}
|
||||
|
||||
#
|
||||
# The IPOMAN returns consumed energy in Wh. We want it in J (= Ws), in order for munin to graph in W.
|
||||
#
|
||||
if ($energy ne 'U') {
|
||||
$energy = $energy*3600;
|
||||
}
|
||||
|
||||
print "realpower.value ", $energy, "\n";
|
||||
print "apparentpower.value ", $apparentpower, "\n";
|
||||
}
|
||||
exit 0;
|
240
plugins/power/snmp__sentry
Executable file
240
plugins/power/snmp__sentry
Executable file
|
@ -0,0 +1,240 @@
|
|||
#!/usr/bin/perl -w
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Munin plugin snmp__sentry is written to monitor the Sentry line of Power Distribution Units (PDU) offered by Server Technology.
|
||||
|
||||
This plugin currently assumes a 3-phase PDU.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Danny Howard <dannyman@toldme.com>
|
||||
|
||||
This plugin was created on the behalf of Quantifind, Inc. http://www.quantifind.com
|
||||
|
||||
=head1 LICENSE
|
||||
|
||||
BSD
|
||||
|
||||
=head1 MAGIC MARKERS
|
||||
|
||||
#%# family=snmpauto
|
||||
#%# capabilities=snmpconf
|
||||
|
||||
=head1 EXAMPLE MIB
|
||||
|
||||
$ wget ftp://ftp.servertech.com/pub/SNMP/sentry3/Sentry3.mib
|
||||
$ snmpwalk -c public -v 2c -M +. -m +Sentry3-MIB 192.168.whatevs .1.3.6.1.4.1.1718.3.2.2
|
||||
Sentry3-MIB::infeedID.1.1 = STRING: AA
|
||||
Sentry3-MIB::infeedID.1.2 = STRING: AB
|
||||
Sentry3-MIB::infeedID.1.3 = STRING: AC
|
||||
Sentry3-MIB::infeedName.1.1 = STRING: Master_X
|
||||
Sentry3-MIB::infeedName.1.2 = STRING: Master_Y
|
||||
Sentry3-MIB::infeedName.1.3 = STRING: Master_Z
|
||||
Sentry3-MIB::infeedCapabilities.1.1 = BITS: C6 00 onSense(0) loadSense(1) voltageSense(5) powerSense(6)
|
||||
Sentry3-MIB::infeedCapabilities.1.2 = BITS: C6 00 onSense(0) loadSense(1) voltageSense(5) powerSense(6)
|
||||
Sentry3-MIB::infeedCapabilities.1.3 = BITS: C6 00 onSense(0) loadSense(1) voltageSense(5) powerSense(6)
|
||||
Sentry3-MIB::infeedStatus.1.1 = INTEGER: on(1)
|
||||
Sentry3-MIB::infeedStatus.1.2 = INTEGER: on(1)
|
||||
Sentry3-MIB::infeedStatus.1.3 = INTEGER: on(1)
|
||||
Sentry3-MIB::infeedLoadStatus.1.1 = INTEGER: normal(0)
|
||||
Sentry3-MIB::infeedLoadStatus.1.2 = INTEGER: normal(0)
|
||||
Sentry3-MIB::infeedLoadStatus.1.3 = INTEGER: normal(0)
|
||||
Sentry3-MIB::infeedLoadValue.1.1 = INTEGER: 717 hundredth Amps
|
||||
Sentry3-MIB::infeedLoadValue.1.2 = INTEGER: 708 hundredth Amps
|
||||
Sentry3-MIB::infeedLoadValue.1.3 = INTEGER: 787 hundredth Amps
|
||||
Sentry3-MIB::infeedLoadHighThresh.1.1 = INTEGER: 16 Amps
|
||||
Sentry3-MIB::infeedLoadHighThresh.1.2 = INTEGER: 16 Amps
|
||||
Sentry3-MIB::infeedLoadHighThresh.1.3 = INTEGER: 16 Amps
|
||||
Sentry3-MIB::infeedOutletCount.1.1 = INTEGER: 10
|
||||
Sentry3-MIB::infeedOutletCount.1.2 = INTEGER: 10
|
||||
Sentry3-MIB::infeedOutletCount.1.3 = INTEGER: 10
|
||||
Sentry3-MIB::infeedCapacity.1.1 = INTEGER: 20 Amps
|
||||
Sentry3-MIB::infeedCapacity.1.2 = INTEGER: 20 Amps
|
||||
Sentry3-MIB::infeedCapacity.1.3 = INTEGER: 20 Amps
|
||||
Sentry3-MIB::infeedVoltage.1.1 = INTEGER: 2055 tenth Volts
|
||||
Sentry3-MIB::infeedVoltage.1.2 = INTEGER: 2034 tenth Volts
|
||||
Sentry3-MIB::infeedVoltage.1.3 = INTEGER: 2052 tenth Volts
|
||||
Sentry3-MIB::infeedPower.1.1 = INTEGER: 726 Watts
|
||||
Sentry3-MIB::infeedPower.1.2 = INTEGER: 809 Watts
|
||||
Sentry3-MIB::infeedPower.1.3 = INTEGER: 874 Watts
|
||||
Sentry3-MIB::infeedApparentPower.1.1 = INTEGER: 793 Volt-Amps
|
||||
Sentry3-MIB::infeedApparentPower.1.2 = INTEGER: 876 Volt-Amps
|
||||
Sentry3-MIB::infeedApparentPower.1.3 = INTEGER: 941 Volt-Amps
|
||||
Sentry3-MIB::infeedPowerFactor.1.1 = INTEGER: 92 hundredths
|
||||
Sentry3-MIB::infeedPowerFactor.1.2 = INTEGER: 92 hundredths
|
||||
Sentry3-MIB::infeedPowerFactor.1.3 = INTEGER: 93 hundredths
|
||||
Sentry3-MIB::infeedCrestFactor.1.1 = INTEGER: 18 tenths
|
||||
Sentry3-MIB::infeedCrestFactor.1.2 = INTEGER: 17 tenths
|
||||
Sentry3-MIB::infeedCrestFactor.1.3 = INTEGER: 17 tenths
|
||||
Sentry3-MIB::infeedEnergy.1.1 = INTEGER: 762 tenth Kilowatt-Hours
|
||||
Sentry3-MIB::infeedEnergy.1.2 = INTEGER: 913 tenth Kilowatt-Hours
|
||||
Sentry3-MIB::infeedEnergy.1.3 = INTEGER: 928 tenth Kilowatt-Hours
|
||||
Sentry3-MIB::infeedReactance.1.1 = INTEGER: capacitive(1)
|
||||
Sentry3-MIB::infeedReactance.1.2 = INTEGER: capacitive(1)
|
||||
Sentry3-MIB::infeedReactance.1.3 = INTEGER: capacitive(1)
|
||||
Sentry3-MIB::infeedPhaseVoltage.1.1 = INTEGER: 2055 tenth Volts
|
||||
Sentry3-MIB::infeedPhaseVoltage.1.2 = INTEGER: 2034 tenth Volts
|
||||
Sentry3-MIB::infeedPhaseVoltage.1.3 = INTEGER: 2052 tenth Volts
|
||||
Sentry3-MIB::infeedPhaseCurrent.1.1 = INTEGER: 386 hundredth Amps
|
||||
Sentry3-MIB::infeedPhaseCurrent.1.2 = INTEGER: 431 hundredth Amps
|
||||
Sentry3-MIB::infeedPhaseCurrent.1.3 = INTEGER: 459 hundredth Amps
|
||||
Sentry3-MIB::infeedCapacityUsed.1.1 = INTEGER: 358 tenth percentage
|
||||
Sentry3-MIB::infeedCapacityUsed.1.2 = INTEGER: 354 tenth percentage
|
||||
Sentry3-MIB::infeedCapacityUsed.1.3 = INTEGER: 393 tenth percentage
|
||||
Sentry3-MIB::infeedLineID.1.1 = STRING: A:X
|
||||
Sentry3-MIB::infeedLineID.1.2 = STRING: A:Y
|
||||
Sentry3-MIB::infeedLineID.1.3 = STRING: A:Z
|
||||
Sentry3-MIB::infeedLineToLineID.1.1 = STRING: A:X-Y
|
||||
Sentry3-MIB::infeedLineToLineID.1.2 = STRING: A:Y-Z
|
||||
Sentry3-MIB::infeedLineToLineID.1.3 = STRING: A:Z-X
|
||||
Sentry3-MIB::infeedPhaseID.1.1 = STRING: A:X-Y
|
||||
Sentry3-MIB::infeedPhaseID.1.2 = STRING: A:Y-Z
|
||||
Sentry3-MIB::infeedPhaseID.1.3 = STRING: A:Z-X
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use Munin::Plugin::SNMP;
|
||||
|
||||
if (defined $ARGV[0] and $ARGV[0] eq "snmpconf") {
|
||||
print "require 1.3.6.1.4.1.1718.3.2.2.1\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
my $session = Munin::Plugin::SNMP->session(-translate =>
|
||||
[ -timeticks => 0x0 ]);
|
||||
|
||||
my $sentry_h = $session->get_hash (
|
||||
-baseoid => ".1.3.6.1.4.1.1718.3.2.2.1",
|
||||
-cols => {
|
||||
# maxcols 16 I guess
|
||||
# 2 => 'infeedID',
|
||||
3 => 'infeedName',
|
||||
# 4 => 'infeedCapabilities',
|
||||
# 5 => 'infeedStatus',
|
||||
# 6 => 'infeedLoadStatus',
|
||||
7 => 'infeedLoadValue',
|
||||
8 => 'infeedLoadHighThresh',
|
||||
# 9 => 'infeedOutletCount',
|
||||
10 => 'infeedCapacity',
|
||||
# 11 => 'infeedVoltage',
|
||||
# 12 => 'infeedPower',
|
||||
# 13 => 'infeedApparentPower',
|
||||
14 => 'infeedPowerFactor',
|
||||
15 => 'infeedCrestFactor',
|
||||
# 16 => 'infeedEnergy',
|
||||
# 17 => 'infeedReactance',
|
||||
# 18 => 'infeedPhaseVoltage',
|
||||
# 19 => 'infeedPhaseCurrent',
|
||||
# 20 => 'infeedCapacityUsed',
|
||||
# 21 => 'infeedLineID',
|
||||
# 22 => 'infeedLineToLineID',
|
||||
# 23 => 'infeedPhaseID',
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
if (defined $ARGV[0] and $ARGV[0] eq "config") {
|
||||
my ($host) = Munin::Plugin::SNMP->config_session();
|
||||
print "host_name $host\n" unless $host eq 'localhost';
|
||||
print "
|
||||
multigraph power_amps_drawn
|
||||
graph_title Power Draw in Amps
|
||||
graph_args --lower-limit 0
|
||||
graph_vlabel Amps
|
||||
graph_category sensors
|
||||
graph_scale no
|
||||
graph_info This shows the amperage drawn on your PDU. Per NEC, a PDU should not sustain 80% of its maximum circuit capacity for more than three hours.
|
||||
|
||||
";
|
||||
|
||||
foreach my $k ( keys %{$sentry_h} ) {
|
||||
my $infeedName = $sentry_h->{$k}->{'infeedName'};
|
||||
my $critical = ($sentry_h->{$k}->{'infeedCapacity'})*.9; # 90% of capacity
|
||||
my $warning = $sentry_h->{$k}->{'infeedLoadHighThresh'}; # 80% of capacity
|
||||
|
||||
print "$infeedName.critical $critical\n";
|
||||
print "$infeedName.draw LINE1\n";
|
||||
print "$infeedName.label $infeedName\n";
|
||||
print "$infeedName.min 0\n";
|
||||
print "$infeedName.type GAUGE\n";
|
||||
print "$infeedName.warning $warning\n";
|
||||
}
|
||||
|
||||
print "
|
||||
multigraph power_power_factor
|
||||
graph_title Power Factor
|
||||
graph_args --lower-limit 0
|
||||
graph_vlabel Power Factor
|
||||
graph_category sensors
|
||||
graph_scale no
|
||||
graph_info Power factor represents the efficiency of the components connected to the circuit. Power factor declines as components age, increasing the overall load on the circuit.
|
||||
|
||||
";
|
||||
|
||||
foreach my $k ( keys %{$sentry_h} ) {
|
||||
my $infeedName = $sentry_h->{$k}->{'infeedName'};
|
||||
|
||||
print "$infeedName.draw LINE1\n";
|
||||
print "$infeedName.label $infeedName\n";
|
||||
print "$infeedName.type GAUGE\n";
|
||||
}
|
||||
|
||||
print "
|
||||
multigraph power_crest_factor
|
||||
graph_title Crest Factor
|
||||
graph_args --lower-limit 0
|
||||
graph_vlabel Crest Factor
|
||||
graph_category sensors
|
||||
graph_scale no
|
||||
graph_info Crest factor relates the peak value of a signal to its root mean square value. For three-phase AC, a crest factor of 1.732 is expected. Low crest factor may indicate UPS overclipping and crest factors over 5 degrade monitoring accuracy.
|
||||
|
||||
";
|
||||
|
||||
foreach my $k ( keys %{$sentry_h} ) {
|
||||
my $infeedName = $sentry_h->{$k}->{'infeedName'};
|
||||
|
||||
print "$infeedName.draw LINE1\n";
|
||||
print "$infeedName.label $infeedName\n";
|
||||
print "$infeedName.type GAUGE\n";
|
||||
}
|
||||
|
||||
exit 0;
|
||||
}
|
||||
|
||||
print "multigraph power_amps_drawn\n";
|
||||
foreach my $k ( keys %{$sentry_h} ) {
|
||||
my $infeedName = $sentry_h->{$k}->{'infeedName'};
|
||||
my $amps = $sentry_h->{$k}->{'infeedLoadValue'};
|
||||
if ( $amps ) {
|
||||
$amps = $amps * .01;
|
||||
} else {
|
||||
$amps = 'U';
|
||||
}
|
||||
print "$infeedName.value $amps\n";
|
||||
}
|
||||
|
||||
print "multigraph power_power_factor\n";
|
||||
foreach my $k ( keys %{$sentry_h} ) {
|
||||
my $infeedName = $sentry_h->{$k}->{'infeedName'};
|
||||
my $pf = $sentry_h->{$k}->{'infeedPowerFactor'};
|
||||
if ( $pf ) {
|
||||
$pf = $pf * .01;
|
||||
} else {
|
||||
$pf = 'U';
|
||||
}
|
||||
print "$infeedName.value $pf\n";
|
||||
}
|
||||
|
||||
print "multigraph power_crest_factor\n";
|
||||
foreach my $k ( keys %{$sentry_h} ) {
|
||||
my $infeedName = $sentry_h->{$k}->{'infeedName'};
|
||||
my $crest = $sentry_h->{$k}->{'infeedCrestFactor'};
|
||||
if ( $crest ) {
|
||||
$crest = $crest * .1;
|
||||
} else {
|
||||
$crest = 'U';
|
||||
}
|
||||
print "$infeedName.value $crest\n";
|
||||
}
|
217
plugins/power/snmp__ups_
Executable file
217
plugins/power/snmp__ups_
Executable file
|
@ -0,0 +1,217 @@
|
|||
#!/usr/bin/perl -w
|
||||
#
|
||||
# This plugin is for querying UPSes that support the UPS-MIB from RFC 1628
|
||||
# - NOT APC (apparently)
|
||||
#
|
||||
# current version by Michael Meier <michael.meier@fau.de>
|
||||
# previous version by Jean-Samuel Reynaud <js.reynaud@free.fr>
|
||||
# based on snmp__if_ from Jimmy Olsen, Dagfinn Ilmari Mannsaaker
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; version 2 dated June,
|
||||
# 1991.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
#
|
||||
# Usage:
|
||||
# ln -s /usr/share/munin/node/plugins-auto/snmp__ups_ /etc/munin/node.d/snmp_ups.domain.tld_ups_mode
|
||||
# available modes:
|
||||
# batteryruntime, batteryremaining, batterypercent, batteryvoltage,
|
||||
# batterycurrent, batterytemperature,
|
||||
# inputfrequency, inputvoltage, inputcurrent, inputpower,
|
||||
# outputvoltage, outputcurrent, outputpower, outputpercentload,
|
||||
# inputlinebads
|
||||
# Most UPSs only support a small subset of these modes.
|
||||
#
|
||||
|
||||
#%# family=snmpauto
|
||||
#%# capabilities=snmpconf
|
||||
|
||||
use strict;
|
||||
use Net::SNMP;
|
||||
|
||||
my $DEBUG = 0;
|
||||
|
||||
my $host = $ENV{host} || undef;
|
||||
my $port = $ENV{port} || 161;
|
||||
my $community = $ENV{community} || "public";
|
||||
my $mode = $ENV{mode} || undef;
|
||||
|
||||
my $response;
|
||||
|
||||
if (defined $ARGV[0] and $ARGV[0] eq "snmpconf")
|
||||
{
|
||||
print "require .1.3.6.1.2.1.33.1.2.7 [0-9]\n"; # Bat temp
|
||||
exit 0;
|
||||
}
|
||||
|
||||
if ($0 =~ /^(?:|.*\/)snmp_([^_]+)_ups_(.+)$/)
|
||||
{
|
||||
$host = $1;
|
||||
$mode = $2;
|
||||
if ($host =~ /^([^:]+):(\d+)$/) {
|
||||
$host = $1;
|
||||
$port = $2;
|
||||
}
|
||||
}
|
||||
elsif (!defined($host))
|
||||
{
|
||||
print("# Debug: $0 -- $1 -- $2\n") if $DEBUG;
|
||||
print("# Error: couldn't understand what I'm supposed to monitor.\n");
|
||||
print("# You need to either name this plugin properly in the scheme\n");
|
||||
print("# snmp_HOSTNAME_ups_MODE\n");
|
||||
print("# or alternatively set the environment variables 'host' and 'mode'\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
my $graphs = {
|
||||
'batteryruntime' => { 'title' => 'Seconds running on battery',
|
||||
'unit' => 'seconds',
|
||||
'label' => 'onbatteryfor',
|
||||
'value' => '.1.3.6.1.2.1.33.1.2.2' },
|
||||
'batteryremaining' => { 'title' => 'Estimated remaining runtime on battery',
|
||||
'unit' => 'minutes',
|
||||
'label' => 'remaining',
|
||||
'value' => '.1.3.6.1.2.1.33.1.2.3' },
|
||||
'batterypercent' => { 'title' => 'Estimated remaining charge',
|
||||
'unit' => '%',
|
||||
'label' => 'remaining',
|
||||
'value' => '.1.3.6.1.2.1.33.1.2.4' },
|
||||
'batteryvoltage' => { 'title' => 'Battery Voltage',
|
||||
'unit' => 'Volt',
|
||||
'scale' => 0.1,
|
||||
'value' => '.1.3.6.1.2.1.33.1.2.5' },
|
||||
'batterycurrent' => { 'title' => 'Battery current',
|
||||
'unit' => 'Ampere',
|
||||
'scale' => 0.1,
|
||||
'value' => '.1.3.6.1.2.1.33.1.2.6' },
|
||||
'batterytemperature' => { 'title' => 'Battery Temperature',
|
||||
'unit' => 'degC',
|
||||
'label' => 'Temperature %u',
|
||||
'value' => '.1.3.6.1.2.1.33.1.2.7' },
|
||||
'inputfrequency' => { 'title' => 'Input Frequency',
|
||||
'scale' => 0.1,
|
||||
'unit' => 'Hz',
|
||||
'list' => '.1.3.6.1.2.1.33.1.3.2',
|
||||
'value' => '.1.3.6.1.2.1.33.1.3.3.1.2' },
|
||||
'inputvoltage' => { 'title' => 'Input Voltage',
|
||||
'unit' => 'Volt',
|
||||
'list' => '.1.3.6.1.2.1.33.1.3.2',
|
||||
'value' => '.1.3.6.1.2.1.33.1.3.3.1.3' },
|
||||
'inputcurrent' => { 'title' => 'Input Current',
|
||||
'unit' => 'Ampere',
|
||||
'scale' => 0.1,
|
||||
'list' => '.1.3.6.1.2.1.33.1.3.2',
|
||||
'value' => '.1.3.6.1.2.1.33.1.3.3.1.4' },
|
||||
'inputpower' => { 'title' => 'Input Power',
|
||||
'unit' => 'Watt',
|
||||
'list' => '.1.3.6.1.2.1.33.1.3.2',
|
||||
'value' => '.1.3.6.1.2.1.33.1.3.3.1.5' },
|
||||
'outputvoltage' => { 'title' => 'Output Voltage',
|
||||
'list' => '.1.3.6.1.2.1.33.1.4.3',
|
||||
'unit' => 'Volt',
|
||||
'value' => '.1.3.6.1.2.1.33.1.4.4.1.2' },
|
||||
'outputcurrent' => { 'title' => 'Output Current',
|
||||
'unit' => 'Ampere',
|
||||
'scale' => 0.1,
|
||||
'list' => '.1.3.6.1.2.1.33.1.4.3',
|
||||
'value' => '.1.3.6.1.2.1.33.1.4.4.1.3' },
|
||||
'outputpower' => { 'title' => 'Output Power',
|
||||
'unit' => 'Watt',
|
||||
'list' => '.1.3.6.1.2.1.33.1.4.3',
|
||||
'value' => '.1.3.6.1.2.1.33.1.4.4.1.4' },
|
||||
'outputpercentload' => { 'title' => 'Output Load',
|
||||
'unit' => '%',
|
||||
'list' => '.1.3.6.1.2.1.33.1.4.3',
|
||||
'value' => '.1.3.6.1.2.1.33.1.4.4.1.5' },
|
||||
'inputlinebads' => { 'title' => 'Number of times input power went bad',
|
||||
'unit' => 'n',
|
||||
'value' => '.1.3.6.1.2.1.33.1.3.1' }
|
||||
};
|
||||
|
||||
|
||||
my ($session, $error) = Net::SNMP->session(
|
||||
-hostname => $host,
|
||||
-community => $community,
|
||||
-port => $port,
|
||||
-timeout => 1.0
|
||||
);
|
||||
|
||||
if (!defined($session)) {
|
||||
print("# Failed to open SNMP session: $error\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
unless (defined($graphs->{$mode}->{'title'})) {
|
||||
print("# Unknown mode '$mode'! Available modes are:\n");
|
||||
foreach my $m (keys(%{$graphs})) {
|
||||
if (defined($graphs->{$m}->{'title'})) {
|
||||
printf("# %-18s %s\n", $m, $graphs->{$m}->{'title'});
|
||||
}
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
my $count_data = 1;
|
||||
if (defined $graphs->{$mode}->{'list'}) {
|
||||
if (defined ($response = $session->get_request($graphs->{$mode}->{'list'} . ".0"))) {
|
||||
$count_data = $response->{$graphs->{$mode}->{'list'} . ".0"};
|
||||
} else { # Unfortunately, some UPSs do not properly implement RFC 1628:
|
||||
# They fail to report the number of lines.
|
||||
# We will default to 3 as that will work in most cases.
|
||||
# The environment variable 'numlines' can be used to override the default.
|
||||
$count_data = 3;
|
||||
if (defined($ENV{'numlines'})) {
|
||||
$count_data = int($ENV{'numlines'});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($ARGV[0] and $ARGV[0] eq "config") {
|
||||
print("host_name $host\n");
|
||||
printf("graph_title %s\n", $graphs->{$mode}->{'title'});
|
||||
# print "graph_args --base 1000\n";
|
||||
print("graph_category sensors\n");
|
||||
printf("graph_vlabel %s\n", $graphs->{$mode}->{'unit'});
|
||||
|
||||
for (my $i=0; $i < $count_data; $i++) {
|
||||
my $ip1 = $i + 1;
|
||||
if (defined($graphs->{$mode}->{'label'})) {
|
||||
printf("%s%u.label %s\n", $mode, $ip1, sprintf($graphs->{$mode}->{'label'}, $ip1));
|
||||
} else {
|
||||
printf("%s%u.label Line %u\n", $mode, $ip1, $ip1);
|
||||
}
|
||||
printf("%s%u.type GAUGE\n", $mode, $ip1);
|
||||
#printf "line%u.info %s\n",$i+1,$graphs->{$mode}->{'unit'};
|
||||
if (defined($ENV{"${mode}${ip1}.warning"})) { printf("%s%s.warning %s\n", $mode, $ip1, $ENV{"${mode}${ip1}.warning"}); }
|
||||
if (defined($ENV{"${mode}${ip1}.critical"})) { printf("%s%s.critical %s\n", $mode, $ip1, $ENV{"${mode}${ip1}.critical"}); }
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
for (my $i = 0; $i < $count_data; $i++) {
|
||||
my $l_current = $i+1;
|
||||
if ($count_data == 1) {
|
||||
$l_current = 0;
|
||||
}
|
||||
if (defined ($response = $session->get_request($graphs->{$mode}->{'value'} . sprintf(".%u",$l_current)))) {
|
||||
my $v = $response->{$graphs->{$mode}->{'value'} . sprintf(".%u",$l_current)};
|
||||
if (defined($graphs->{$mode}->{'scale'})) {
|
||||
$v = $v * $graphs->{$mode}->{'scale'};
|
||||
printf("%s%u.value %.1f\n", $mode, $i+1, $v);
|
||||
} else {
|
||||
printf("%s%u.value %u\n", $mode, $i+1, $v);
|
||||
}
|
||||
} else {
|
||||
printf("%s%u.value U\n", $mode, $i+1);
|
||||
}
|
||||
}
|
222
plugins/power/upsmonpro_
Normal file
222
plugins/power/upsmonpro_
Normal file
|
@ -0,0 +1,222 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
=head1 NAME
|
||||
|
||||
upsmonpro_ - Munin plugin to monitor Powercom UPS via UPSMON PRO program L<http://www.pcm.ru/support/soft/>
|
||||
|
||||
=head1 INSTALLATION
|
||||
|
||||
/etc/munin/plugins/upsmonpro_load -> /usr/share/munin/plugins/upsmonpro_
|
||||
/etc/munin/plugins/upsmonpro_status -> /usr/share/munin/plugins/upsmonpro_
|
||||
/etc/munin/plugins/upsmonpro_temp -> /usr/share/munin/plugins/upsmonpro_
|
||||
/etc/munin/plugins/upsmonpro_voltage -> /usr/share/munin/plugins/upsmonpro_
|
||||
|
||||
=head1 CONFIGURATION
|
||||
|
||||
Environment variables:
|
||||
|
||||
host - UPSMON PRO server host, default localhost
|
||||
port - UPSMON PRO port, default 2601
|
||||
|
||||
Example configuration (optional):
|
||||
|
||||
[upsmonpro_*]
|
||||
env.host localhost
|
||||
env.port 2601
|
||||
|
||||
=head1 MAGIC MARKERS
|
||||
|
||||
#%# family=auto
|
||||
#%# capabilities=autoconf
|
||||
#%# capabilities=suggest
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Copyright (C) 2017 pru.mike@gmail.com
|
||||
|
||||
=head1 LICENSE
|
||||
|
||||
GPLv2.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use feature qw/say/;
|
||||
use Munin::Plugin;
|
||||
use IO::Socket::INET;
|
||||
use Time::HiRes qw/usleep/;
|
||||
use English qw/-no-math-vars/;
|
||||
our $VERSION = '0.0.1';
|
||||
$OUTPUT_AUTOFLUSH++;
|
||||
|
||||
our $DEFAULT_HOST = 'localhost';
|
||||
our $DEFAULT_PORT = 2601;
|
||||
our %TYPES = (
|
||||
voltage => [qw/input output/],
|
||||
load => [qw/battery_load battery_capacity/],
|
||||
temp => [q/temp/],
|
||||
status => [qw/power_failure low_battery voltage_status ups_status battery_test/]
|
||||
);
|
||||
our @TYPES = sort keys %TYPES;
|
||||
my %DISPATCH_TABLE = ();
|
||||
my $pkg = __PACKAGE__;
|
||||
|
||||
$DISPATCH_TABLE{"${pkg}::run_suggest"} = \&run_suggest;
|
||||
$DISPATCH_TABLE{"${pkg}::run_autoconf"} = \&run_autoconf;
|
||||
for my $t (@TYPES) {
|
||||
$DISPATCH_TABLE{"${pkg}::run_config_$t"} = \&{"run_config_$t"};
|
||||
$DISPATCH_TABLE{"${pkg}::run_autoconf_$t"} = \&run_autoconf;
|
||||
$DISPATCH_TABLE{"${pkg}::run_default_$t"} = sub {
|
||||
run_default(@{ $TYPES{$t} });
|
||||
};
|
||||
}
|
||||
|
||||
find_key($ARGV[0])->();
|
||||
|
||||
sub find_key {
|
||||
my $argv = shift || '';
|
||||
my $type_re = join '|', @TYPES;
|
||||
my $key;
|
||||
if ($argv =~ /(suggest|autoconf)/i) {
|
||||
$key = 'run_' . lc($1);
|
||||
} elsif ($Munin::Plugin::me =~ /upsmonpro_{1,}($type_re)$/) {
|
||||
my $graph = $1;
|
||||
$key = 'run_' . ((grep { $argv eq $_ } qw/autoconf config/) ? $argv : 'default') . "_$graph";
|
||||
} else {
|
||||
die "Could not determine script type [@TYPES] ? name=$Munin::Plugin::me\n";
|
||||
}
|
||||
|
||||
return $DISPATCH_TABLE{"${pkg}::$key"};
|
||||
}
|
||||
|
||||
sub run_config_voltage {
|
||||
print <<'END';
|
||||
graph_title UPS Input/Output Voltage
|
||||
graph_vlabel volt
|
||||
graph_scale no
|
||||
graph_category sensors
|
||||
input.label input
|
||||
input.info Input Voltage
|
||||
input.type GAUGE
|
||||
output.label output
|
||||
output.info Output Voltage
|
||||
output.type GAUGE
|
||||
END
|
||||
exit(0);
|
||||
}
|
||||
|
||||
sub run_config_temp {
|
||||
print <<'END';
|
||||
graph_title UPS Temperature
|
||||
graph_vlabel celsius
|
||||
graph_scale no
|
||||
graph_category sensors
|
||||
temp.label temperature
|
||||
temp.type GAUGE
|
||||
END
|
||||
exit(0);
|
||||
}
|
||||
|
||||
sub run_config_load {
|
||||
print <<'END';
|
||||
graph_title UPS Battery Load/Capacity
|
||||
graph_vlabel precent%
|
||||
graph_scale no
|
||||
graph_category sensors
|
||||
battery_load.label battery_load
|
||||
battery_load.type GAUGE
|
||||
battery_capacity.label battery_capacity
|
||||
battery_capacity.type GAUGE
|
||||
END
|
||||
exit(0);
|
||||
}
|
||||
|
||||
sub run_config_status {
|
||||
print <<'END';
|
||||
graph_title UPS Statuses
|
||||
graph_vlabel status
|
||||
graph_scale no
|
||||
graph_category sensors
|
||||
power_failure.label power_failure
|
||||
power_failure.type GAUGE
|
||||
low_battery.label low_battery
|
||||
low_battery.type GAUGE
|
||||
voltage_status.label voltage_status
|
||||
voltage_status.info 0 normal, 1 boost, 2 buck
|
||||
voltage_status.type GAUGE
|
||||
ups_status.label ups_status
|
||||
ups_status.type GAUGE
|
||||
battery_test.label battery_test
|
||||
battery_test.type GAUGE
|
||||
END
|
||||
exit(0);
|
||||
}
|
||||
|
||||
sub run_default {
|
||||
my $host = $ENV{host} || $DEFAULT_HOST;
|
||||
my $port = $ENV{port} || $DEFAULT_PORT;
|
||||
my @val_list = @_;
|
||||
my $r = gather_data($host, $port);
|
||||
for (@val_list) {
|
||||
die "Wrong value: $_" if not exists $r->{$_};
|
||||
say "${_}.value $r->{$_}";
|
||||
}
|
||||
}
|
||||
|
||||
sub run_suggest {
|
||||
local $LIST_SEPARATOR = "\n";
|
||||
say "@TYPES";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
sub run_autoconf {
|
||||
if (gather_data($DEFAULT_HOST, $DEFAULT_PORT)->{response} eq 'ok') {
|
||||
say "yes";
|
||||
} else {
|
||||
say "no ($DEFAULT_HOST:$DEFAULT_PORT not response)";
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
sub gather_data {
|
||||
my $host = shift;
|
||||
my $port = shift;
|
||||
my %data = map { ($_ => 'U') } map { @{ $TYPES{$_} } } @TYPES;
|
||||
$data{response} = 'failed';
|
||||
|
||||
my $sock = IO::Socket::INET->new(
|
||||
PeerAddr => $host,
|
||||
Proto => 'udp',
|
||||
PeerPort => $port,
|
||||
Blocking => 0
|
||||
) or die "Cannot create socket: $@";
|
||||
|
||||
my $pattern = pack 'AAAACAAA', split //, 'PCMG1END';
|
||||
$sock->send($pattern) or die "send to $host: $!";
|
||||
usleep(200);
|
||||
my $data;
|
||||
my $buf;
|
||||
while ($sock->read($buf, 32)) {
|
||||
$data .= $buf;
|
||||
}
|
||||
if (defined $data and $data =~ /^PCMR.*END$/) {
|
||||
my @data = unpack('C*', $data);
|
||||
%data = (
|
||||
response => 'ok',
|
||||
input => $data[6] + 256 * $data[5],
|
||||
output => $data[8] + 256 * $data[7],
|
||||
battery_load => $data[11],
|
||||
battery_capacity => $data[12],
|
||||
temp => $data[15],
|
||||
power_failure => ($data[18] ? 1 : 0),
|
||||
low_battery => ($data[19] ? 1 : 0),
|
||||
|
||||
#voltage_status: 0 = normal, 3 = buck, 2 = boost
|
||||
voltage_status => ($data[17] == 0 ? 0 : ($data[17] == 3 ? 2 : 1)),
|
||||
ups_status => ($data[21] ? 1 : 0),
|
||||
battery_test => ($data[23] ? 1 : 0),
|
||||
);
|
||||
}
|
||||
return \%data;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue