mirror of
https://github.com/munin-monitoring/contrib.git
synced 2018-11-08 00:59:34 +01:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
54dee0ad42
@ -7,12 +7,15 @@
|
||||
|
||||
=head1 AUTHOR AND COPYRIGHT
|
||||
|
||||
Copyright 2011-2012 Luc Didry <luc AT didry.org>
|
||||
Copyright 2011-2014 Luc Didry <luc AT didry.org>
|
||||
|
||||
=head1 HOWTO CONFIGURE AND USE :
|
||||
|
||||
=over
|
||||
|
||||
=item - /etc/munin/plugins/du
|
||||
cp du /etc/munin/plugins/
|
||||
|
||||
=item - /etc/munin/plugin-conf.d/du_
|
||||
|
||||
[du]
|
||||
@ -22,14 +25,9 @@
|
||||
env.suppr /home/ # PLEASE USE \# INSTEAD OF #
|
||||
timeout 900 # 15 MINUTES IN SECONDS
|
||||
|
||||
=item - /etc/munin/plugins-enabled
|
||||
|
||||
ln -svf ../plugins-available/site/du
|
||||
|
||||
|
||||
=item - restart Munin node
|
||||
|
||||
sudo killall -TERM munin-node
|
||||
/etc/init.d/munin-node restart
|
||||
|
||||
=back
|
||||
|
||||
@ -73,7 +71,7 @@ my $TIMEFILE="$Munin::Plugin::pluginstatedir/du.time";
|
||||
|
||||
##### autoconf
|
||||
if( (defined $ARGV[0]) && ($ARGV[0] eq "autoconf") ) {
|
||||
print "yes\n";
|
||||
print "no\n";
|
||||
## Done !
|
||||
munin_exit_done();
|
||||
}
|
||||
|
78
plugins/disk/du_pattern
Executable file
78
plugins/disk/du_pattern
Executable file
@ -0,0 +1,78 @@
|
||||
#!/bin/sh
|
||||
# -*- sh -*-
|
||||
# vim: ft=sh
|
||||
|
||||
: << =cut
|
||||
|
||||
=head1 NAME
|
||||
|
||||
du_pattern - plugin to monitor files size selected and grouped by a pattern
|
||||
|
||||
=head1 CONFIGURATION
|
||||
|
||||
[du_pattern]
|
||||
env.DIR /var/log/apache/
|
||||
env.PATTERN www.example.com www.sample.com
|
||||
|
||||
In PATTERN, all items will be expanded like this : www.example.com*
|
||||
In this example, you will monitor the size of :
|
||||
/var/log/apache/www.example.com*
|
||||
/var/log/apache/www.sample.com*
|
||||
|
||||
It's useful if you want to graph the size of your sites' log archives for example,
|
||||
one graph per site.
|
||||
|
||||
=head1 AUTHOR AND COPYRIGHT
|
||||
|
||||
Copyright 2013-2014 Luc Didry <luc AT didry.org>
|
||||
|
||||
=head1 LICENSE
|
||||
|
||||
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, either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
=cut
|
||||
|
||||
NAME=${0##*/du_pattern_}
|
||||
|
||||
if [ "$1" = "config" ]; then
|
||||
echo "multigraph du_pattern_${NAME}"
|
||||
echo "graph_title Files size in ${DIR}"
|
||||
echo "graph_vlabel size of files"
|
||||
echo "graph_category disk"
|
||||
echo "graph_total Total"
|
||||
echo "graph_info This graph shows the size of files grouped by a pattern."
|
||||
FIRST=1
|
||||
for i in ${PATTERN}
|
||||
do
|
||||
CLEAN=${i//\./_}
|
||||
echo "$CLEAN.label $CLEAN"
|
||||
if [[ $FIRST -eq 1 ]]
|
||||
then
|
||||
echo "$CLEAN.draw AREA"
|
||||
FIRST=0
|
||||
else
|
||||
echo "$CLEAN.draw STACK"
|
||||
fi
|
||||
done
|
||||
exit 0
|
||||
fi
|
||||
|
||||
for i in ${PATTERN}
|
||||
do
|
||||
CLEAN=${i//\./_}
|
||||
FILES="${DIR}/${i}*"
|
||||
echo -n "$CLEAN.value "
|
||||
echo $(du -cbs ${FILES} | grep total | cut -f 1)
|
||||
done
|
||||
exit 0
|
@ -14,6 +14,7 @@
|
||||
# - connect to a running ejabberd node
|
||||
#
|
||||
# OS: *NIX
|
||||
# Requires lsof/fstat for open_files.
|
||||
#
|
||||
# Author: Artem Sheremet <dot.doom@gmail.com>
|
||||
#
|
||||
@ -120,7 +121,7 @@ code.info The total amount of memory currently allocated for Erlang code. This m
|
||||
ets.info The total amount of memory currently allocated for ets tables. This memory is part of the memory presented as system memory.
|
||||
INFO_FROM_DOC
|
||||
else
|
||||
pid=$(<$EJABBERD_PID_PATH)
|
||||
local pid=$(<$EJABBERD_PID_PATH)
|
||||
for memory_type in rss vsz; do
|
||||
memory_value=$(ps -p $pid -o $memory_type=)
|
||||
let memory_value=$memory_value*1024
|
||||
@ -140,42 +141,69 @@ function ejabberd_report_ports() {
|
||||
local limit=$(ejabberd_exec 'os:getenv("ERL_MAX_PORTS").' | tr '"' ' ')
|
||||
# string "false" indicates that this variable is not defined, thus a default of 1024
|
||||
[ $limit = false ] && limit=1024
|
||||
local os_limit=$(ejabberd_exec 'os:cmd("ulimit -n").' | tr '"\\n' ' ')
|
||||
if [ $limit -gt $os_limit ]; then
|
||||
local real_limit=$os_limit
|
||||
else
|
||||
local real_limit=$limit
|
||||
fi
|
||||
if [ "$1" = "config" ]; then
|
||||
cat <<CONFIG
|
||||
graph_vlabel ports
|
||||
opened.draw LINE
|
||||
opened.label opened
|
||||
opened.info length(erlang:ports())
|
||||
open.draw LINE
|
||||
open.label open
|
||||
open.info length(erlang:ports())
|
||||
limit.draw LINE2
|
||||
limit.label limit
|
||||
limit.info ERL_MAX_PORTS environment variable inside ejabberd
|
||||
os_limit.draw LINE2
|
||||
os_limit.label os limit
|
||||
os_limit.info "ulimit -n" from inside of ejabberd
|
||||
CONFIG
|
||||
warning='80%' critical='90%' print_adjusted_thresholds opened $real_limit
|
||||
warning='80%' critical='90%' print_adjusted_thresholds open $limit
|
||||
[ -n "$ERL_MAX_PORTS" ] && cat <<CONFIG_CONFIGURED
|
||||
configured.draw LINE
|
||||
configured.label configured
|
||||
configured.info Configuration file value ERL_MAX_PORTS
|
||||
CONFIG_CONFIGURED
|
||||
else
|
||||
local opened=$(ejabberd_exec 'length(erlang:ports()).')
|
||||
local open=$(ejabberd_exec 'length(erlang:ports()).')
|
||||
cat <<DATA
|
||||
opened.value $opened
|
||||
open.value $open
|
||||
limit.value $limit
|
||||
os_limit.value $os_limit
|
||||
DATA
|
||||
[ -n "$ERL_MAX_PORTS" ] && echo "configured.value $ERL_MAX_PORTS"
|
||||
fi
|
||||
}
|
||||
|
||||
function open_files_counter_util() {
|
||||
if hash lsof &>/dev/null; then
|
||||
echo lsof
|
||||
return 0
|
||||
elif hash fstat &>/dev/null; then
|
||||
echo fstat
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
function open_files_number() {
|
||||
echo $[$($(open_files_counter_util) -np $(<$EJABBERD_PID_PATH) | wc -l)-1]
|
||||
}
|
||||
|
||||
function ejabberd_report_open_files() {
|
||||
# this spawns a child process, but in most cases the open files limit is inherited
|
||||
local limit=$(ejabberd_exec 'os:cmd("ulimit -n").' | tr '"\\n' ' ')
|
||||
if [ "$1" = "config" ]; then
|
||||
cat <<CONFIG
|
||||
graph_vlabel open files
|
||||
open.draw LINE
|
||||
open.label open
|
||||
open.info number of open files as reported by $(open_files_counter_util)
|
||||
limit.draw LINE2
|
||||
limit.label limit
|
||||
limit.info "ulimit -n" from inside of ejabberd
|
||||
CONFIG
|
||||
warning='80%' critical='90%' print_adjusted_thresholds open $limit
|
||||
else
|
||||
cat <<DATA
|
||||
open.value $(open_files_number)
|
||||
limit.value $limit
|
||||
DATA
|
||||
fi
|
||||
}
|
||||
|
||||
function ejabberd_report_processes() {
|
||||
local limit=$(ejabberd_exec 'erlang:system_info(process_limit).')
|
||||
if [ "$1" = "config" ]; then
|
||||
@ -217,6 +245,7 @@ ports
|
||||
online_users
|
||||
registered_users
|
||||
SUGGESTIONS
|
||||
open_files_counter_util &>/dev/null && echo open_files
|
||||
exit 0
|
||||
;;
|
||||
config)
|
||||
|
@ -9,17 +9,26 @@
|
||||
# Symlink this file to hadoop_hdfs_block or hadoop_hdfs_capacity to get block
|
||||
# or capacity informations about the DFS.
|
||||
#
|
||||
#
|
||||
# Needs following minimal configuration in plugin-conf.d/munin-node:
|
||||
# [hadoop_hdfs_block]
|
||||
# user hdfs
|
||||
#
|
||||
# [hadoop_hdfs_capacity]
|
||||
# user hdfs
|
||||
#
|
||||
# Author: KARASZI Istvan <muninexchange@spam.raszi.hu>
|
||||
#
|
||||
|
||||
use strict;
|
||||
use File::Basename qw(basename);
|
||||
use Munin::Plugin;
|
||||
|
||||
my $type = &getType($0);
|
||||
|
||||
#
|
||||
# main
|
||||
#
|
||||
my $type = &getType($0);
|
||||
if ($ARGV[0]) {
|
||||
if ($ARGV[0] eq "autoconf") {
|
||||
print "yes\n";
|
||||
@ -95,9 +104,12 @@ sub getCapacity {
|
||||
}
|
||||
|
||||
sub getStatistics {
|
||||
open(DFSADMIN, "hadoop dfsadmin -report|") || die("Cannot open dfsadmin: $!");
|
||||
open(DFSADMIN, "hdfs dfsadmin -report|") || die("Cannot open dfsadmin: $!");
|
||||
while(defined(my $line = <DFSADMIN>)) {
|
||||
chomp($line);
|
||||
if ($line =~ /-------------------------------------------------/) {
|
||||
last
|
||||
}
|
||||
|
||||
if ($type eq "block") {
|
||||
&getBlock($line);
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
if [ "$1" = "config" ]; then
|
||||
echo "graph_title Mailman Queue"
|
||||
echo "graph_category mailman"
|
||||
echo "graph_args --base 1000 -l 0"
|
||||
echo "archive.label Archive"
|
||||
echo "archive.draw LINE2"
|
269
plugins/mail/postfwd2
Executable file
269
plugins/mail/postfwd2
Executable file
@ -0,0 +1,269 @@
|
||||
#!/usr/bin/perl
|
||||
# vim: set filetype=perl sw=4 tabstop=4 expandtab smartindent: #
|
||||
|
||||
=head1 NAME
|
||||
|
||||
postfwd2 - plugin to get stats from postfwd2
|
||||
|
||||
=head1 AUTHOR AND COPYRIGHT
|
||||
|
||||
Copyright 2013-2014 Luc Didry <luc AT didry.org>
|
||||
|
||||
=head1 HOWTO CONFIGURE AND USE :
|
||||
|
||||
=over
|
||||
|
||||
=item - /etc/munin/plugin-conf.d/postfwd2
|
||||
|
||||
[postfwd2]
|
||||
user root
|
||||
env.path /usr/local/sbin/postfwd2 # OPTIONAL : looks for postfwd2 in /bin, /sbin, /usr/bin, /usr/sbin, /usr/local/bin, /usr/local/sbin
|
||||
env.include .*ISBAD #OPTIONAL
|
||||
env.exclude .*ISGOOD #OPTIONAL
|
||||
|
||||
=item - env.include and env.exclude
|
||||
|
||||
This are perl regexp.
|
||||
If env.include is set and env.exclude is not, only the policy which name
|
||||
matchs will be used.
|
||||
If env.exclude is set and env.include is not, only the policy which name NOT
|
||||
matchs will be used.
|
||||
If both are set, a policy which name matchs the both regex will be used, a
|
||||
policy which matchs only the exclude regexp will NOT be used and a policy
|
||||
which match not the exclude regex will be used, even if it not matchs the
|
||||
include regexp.
|
||||
if none are set, all the policy will be used.
|
||||
|
||||
|
||||
=item - /etc/munin/plugins
|
||||
|
||||
cp postfwd2 /etc/munin/plugins
|
||||
|
||||
|
||||
=item - restart Munin node
|
||||
|
||||
service munin-node restart
|
||||
|
||||
=back
|
||||
|
||||
=head1 LICENSE
|
||||
|
||||
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, either version 3 of the License, or any later version.
|
||||
|
||||
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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
=cut
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
use Munin::Plugin;
|
||||
|
||||
need_multigraph();
|
||||
|
||||
my @keys =qw/cache_queries cache_stats policy_requests policy_timeout policy_matchs/;
|
||||
my %graphs = (
|
||||
cache_queries => {
|
||||
title => 'Cache queries',
|
||||
vlabel => 'Nb of cache queries',
|
||||
series => {
|
||||
cache_queries => {
|
||||
label => 'Cache queries',
|
||||
type => 'COUNTER'
|
||||
}
|
||||
},
|
||||
},
|
||||
cache_stats => {
|
||||
title => 'Cache stats',
|
||||
vlabel => 'percent',
|
||||
series => {
|
||||
cache_requests => {
|
||||
label => 'Requests hitrate',
|
||||
type => 'GAUGE'
|
||||
},
|
||||
cache_dns => {
|
||||
label => 'Dns hitrate',
|
||||
type => 'GAUGE'
|
||||
},
|
||||
cache_rates => {
|
||||
label => 'Rates hitrate',
|
||||
type => 'GAUGE'
|
||||
}
|
||||
},
|
||||
},
|
||||
policy_requests => {
|
||||
title => 'Policy requests',
|
||||
vlabel => 'Nb of policy requests',
|
||||
series => {
|
||||
policy_requests => {
|
||||
label => 'Policy requests',
|
||||
type => 'COUNTER'
|
||||
}
|
||||
},
|
||||
},
|
||||
policy_timeout => {
|
||||
title => 'Policy timeout',
|
||||
vlabel => 'Nb of policy timeout',
|
||||
series => {
|
||||
policy_timeout => {
|
||||
label => 'Policy timeout',
|
||||
type => 'COUNTER'
|
||||
}
|
||||
}
|
||||
},
|
||||
policy_matchs => {
|
||||
title => 'Policy matchs',
|
||||
vlabel => 'Matchs percentage'
|
||||
}
|
||||
);
|
||||
|
||||
my $PLUGIN_NAME = 'postfwd2';
|
||||
my $CACHEFILE="$Munin::Plugin::pluginstatedir/postfwd2.cache";
|
||||
|
||||
my ($include, $exclude) = ($ENV{include}, $ENV{exclude});
|
||||
if (defined($include) && (!defined($exclude))) {
|
||||
$exclude = '.*';
|
||||
}
|
||||
|
||||
##### Cache file, to continue to graph old policies which doesn't exist anymore
|
||||
if (!(-f $CACHEFILE) || !(-e $CACHEFILE)) {
|
||||
open (FILE, ">", $CACHEFILE) or munin_exit_fail();
|
||||
close(FILE);
|
||||
}
|
||||
open (FILE, "<", $CACHEFILE) or munin_exit_fail();
|
||||
my @policies = <FILE>;
|
||||
close(FILE);
|
||||
my %policies = map { $_, 1 } @policies;
|
||||
foreach my $policy (keys %policies) {
|
||||
chomp $policy;
|
||||
$graphs{policy_matchs}->{series}->{$policy}->{type} = 'GAUGE';
|
||||
$graphs{policy_matchs}->{series}->{$policy}->{label} = $policy;
|
||||
$graphs{policy_matchs}->{series}->{$policy}->{value} = 0;
|
||||
}
|
||||
|
||||
##### Check postfwd2 path
|
||||
if (!defined($ENV{path}) || !(-x $ENV{path})) {
|
||||
foreach my $path (qw{/bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin}) {
|
||||
$ENV{path} = $path.'/postfwd2' if (!defined($ENV{path}) && -x $path.'/postfwd2');
|
||||
last if (defined($ENV{path}));
|
||||
}
|
||||
}
|
||||
munin_exit_fail() unless (defined($ENV{path}) && -x $ENV{path});
|
||||
|
||||
##### I have to parse the output BEFORE config, since policy matchs are dependant of the postfwd --dumpstats output
|
||||
open(DATA, $ENV{path}.' --dumpstats |') or munin_exit_fail();
|
||||
my $total_requests;
|
||||
while(defined (my $data = <DATA>)) {
|
||||
if ($data =~ m/^\[STATS\] postfwd2::cache .*: (\d+) queries since/) {
|
||||
$graphs{cache_queries}->{series}->{cache_queries}->{value} = $1;
|
||||
}
|
||||
if ($data =~ m/^\[STATS\] Hitrates: ([\.\d]+)% requests, ([\.\d]+)% dns, ([\.\d]+)% rates$/) {
|
||||
$graphs{cache_stats}->{series}->{cache_requests}->{value} = $1;
|
||||
$graphs{cache_stats}->{series}->{cache_dns}->{value} = $2;
|
||||
$graphs{cache_stats}->{series}->{cache_rates}->{value} = $3;
|
||||
}
|
||||
if ($data =~ m/^\[STATS\] postfwd2::policy .*: (\d+) requests since/) {
|
||||
$graphs{policy_requests}->{series}->{policy_requests}->{value} = $1;
|
||||
$total_requests = $1;
|
||||
}
|
||||
if ($data =~ m/^\[STATS\] Timeouts: .*% \((\d+) of \d+ dns queries\)$/) {
|
||||
$graphs{policy_timeout}->{series}->{policy_timeout}->{value} = $1;
|
||||
}
|
||||
if ($data =~ m/^\[STATS\] +(\d+) matches for id: (.*)$/) {
|
||||
my ($value, $label) = ($1, $2);
|
||||
if ( ( !defined($exclude) ) || ( $label !~ m/$exclude/ || ( defined($include) && $label =~ m/$include/ ) ) ) {
|
||||
if (!defined($policies{$label})) {
|
||||
open (FILE, ">>", $CACHEFILE) or munin_exit_fail();
|
||||
print FILE $label, "\n";
|
||||
close(FILE);
|
||||
$graphs{policy_matchs}->{series}->{$label}->{type} = 'GAUGE';
|
||||
$graphs{policy_matchs}->{series}->{$label}->{label} = $label;
|
||||
}
|
||||
$graphs{policy_matchs}->{series}->{$label}->{value} = sprintf("%.2f", 100*$value/$total_requests);
|
||||
}
|
||||
}
|
||||
}
|
||||
close(DATA);
|
||||
|
||||
##### config
|
||||
if( (defined $ARGV[0]) && ($ARGV[0] eq 'config') ) {
|
||||
foreach my $key (@keys) {
|
||||
print 'multigraph postfwd2_', $key, "\n";
|
||||
print 'graph_title Postfwd2 ', $graphs{$key}->{title}, "\n";
|
||||
print 'graph_vlabel ', $graphs{$key}->{vlabel}, "\n";
|
||||
my $args = ($key eq 'cache_stats') ? ' --upper-limit 100 --rigid' : '';
|
||||
print 'graph_args --lower-limit 0', $args, "\n";
|
||||
print 'graph_category mail', "\n";
|
||||
if ($key eq 'policy_matchs') {
|
||||
print 'graph_width 600', "\n";
|
||||
my @pol_keys = sort { $graphs{$key}->{series}->{$b}->{value} <=> $graphs{$key}->{series}->{$a}->{value} } keys %{$graphs{$key}->{series}};
|
||||
foreach my $label (@pol_keys) {
|
||||
print $label, '.label ', $graphs{$key}->{series}->{$label}->{label}, "\n";
|
||||
print $label, '.draw LINE', "\n";
|
||||
print $label, '.type ', $graphs{$key}->{series}->{$label}->{type}, "\n";
|
||||
}
|
||||
foreach my $label (@pol_keys) {
|
||||
print 'multigraph postfwd2_', $key, '.', $label, "\n";
|
||||
print 'graph_title Postfwd2 ', $label, "\n";
|
||||
print 'graph_vlabel ', $graphs{$key}->{vlabel}, "\n";
|
||||
print 'graph_width 600', "\n";
|
||||
print 'graph_args --lower-limit 0 ', $args, "\n";
|
||||
print 'graph_category others', "\n";
|
||||
print $label, '.label ', $graphs{$key}->{series}->{$label}->{label}, "\n";
|
||||
print $label, '.draw LINE', "\n";
|
||||
print $label, '.type GAUGE', "\n";
|
||||
}
|
||||
} else {
|
||||
foreach my $label (keys %{$graphs{$key}->{series}}) {
|
||||
print $label, '.label ', $graphs{$key}->{series}->{$label}->{label}, "\n";
|
||||
print $label, '.draw AREASTACK', "\n";
|
||||
print $label, '.type ', $graphs{$key}->{series}->{$label}->{type}, "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
munin_exit_done();
|
||||
}
|
||||
|
||||
##### fetch
|
||||
foreach my $key (@keys) {
|
||||
print 'multigraph postfwd2_', $key, "\n";
|
||||
if ($key eq 'policy_matchs') {
|
||||
my @pol_keys = sort { $graphs{$key}->{series}->{$b}->{value} <=> $graphs{$key}->{series}->{$a}->{value} } keys %{$graphs{$key}->{series}};
|
||||
foreach my $label (@pol_keys) {
|
||||
print $label, '.value ', $graphs{$key}->{series}->{$label}->{value}, "\n";
|
||||
}
|
||||
foreach my $label (@pol_keys) {
|
||||
print 'multigraph postfwd2_', $key, '.', $label, "\n";
|
||||
print $label, '.value ', $graphs{$key}->{series}->{$label}->{value}, "\n";
|
||||
}
|
||||
} else {
|
||||
foreach my $label (keys %{$graphs{$key}->{series}}) {
|
||||
print $label, '.value ', $graphs{$key}->{series}->{$label}->{value}, "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
munin_exit_done();
|
||||
|
||||
#
|
||||
##
|
||||
### INTERNALS FONCTIONS
|
||||
###############################################################################
|
||||
sub munin_exit_done {
|
||||
munin_exit(0);
|
||||
} ## sub munin_exit_done
|
||||
|
||||
sub munin_exit_fail {
|
||||
munin_exit(1);
|
||||
} ## sub munin_exit_fail
|
||||
|
||||
sub munin_exit {
|
||||
my $exitcode = shift;
|
||||
exit($exitcode) if(defined $exitcode);
|
||||
exit(1);
|
||||
} ## sub munin_exit
|
189
plugins/mysql/mysql_connections_per_user
Executable file
189
plugins/mysql/mysql_connections_per_user
Executable file
@ -0,0 +1,189 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
# Copyright (C) 2008 Rackspace US, Inc. <http://www.rackspace.com>
|
||||
#
|
||||
# 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, see http://www.gnu.org/licenses/gpl.txt
|
||||
#
|
||||
#
|
||||
# This plugin is based off of the Connection Usage
|
||||
# section of the MySQL Connection Health Page
|
||||
#
|
||||
# http://dev.mysql.com/doc/administrator/en/mysql-administrator-health-connection-health.html
|
||||
#
|
||||
# To enable, link mysql_connections to this file. E.g.
|
||||
#
|
||||
# ln -s /usr/share/node/node/plugins/mysql_connections /etc/munin/plugins/mysql_connections
|
||||
#
|
||||
# Revision 1.0 2007/08/03
|
||||
# Created by Justin Shepherd <galstrom21@gmail.com>
|
||||
#
|
||||
# Revision 2.0 2013/01/02
|
||||
# Per user support by anarcat@koumbit.org
|
||||
#
|
||||
# Parameters:
|
||||
#
|
||||
# config
|
||||
# autoconf
|
||||
#
|
||||
# Configuration variables
|
||||
#
|
||||
# mysqlopts - Options to pass to mysql
|
||||
# mysqladmin - Override location of mysqladmin
|
||||
# numusers - Override maximum number of users to display
|
||||
# warning - Override default warning limit
|
||||
# critical - Override default critical limit
|
||||
#
|
||||
#%# family=auto
|
||||
#%# capabilities=autoconf
|
||||
|
||||
use strict;
|
||||
|
||||
# Define the mysqladmin paths, and commands
|
||||
my $MYSQLADMIN = $ENV{mysqladmin} || "mysqladmin";
|
||||
my $TEST_COMMAND = "$MYSQLADMIN $ENV{mysqlopts} processlist";
|
||||
my $MYSQL_VARIABLES = "$MYSQLADMIN $ENV{mysqlopts} extended-status variables";
|
||||
my $warning = $ENV{warning} || "80";
|
||||
my $critical = $ENV{critical} || "90";
|
||||
my $numusers = $ENV{numusers} || 10;
|
||||
|
||||
# Pull in any arguments
|
||||
my $arg = shift();
|
||||
|
||||
# Check to see how the script was called
|
||||
if ($arg eq 'config') {
|
||||
print_graph_information();
|
||||
} elsif ($arg eq 'autoconf') {
|
||||
if (test_service()) { print "yes\n"; }
|
||||
else { print "no\n"; }
|
||||
} else {
|
||||
print_graph_data();
|
||||
}
|
||||
exit;
|
||||
|
||||
sub print_graph_data() {
|
||||
# Define the values that are returned to munin
|
||||
|
||||
# Return the values to Munin
|
||||
my $counts = count_thread_users();
|
||||
my %counts = %{$counts};
|
||||
|
||||
sub valsort {
|
||||
return $counts{$a} <=> $counts{$b};
|
||||
}
|
||||
my $i = 0;
|
||||
my $total = 0;
|
||||
foreach my $user (sort valsort keys(%counts)) {
|
||||
last if $i++ >= $numusers;
|
||||
$total += $counts{$user};
|
||||
print "$user.value $counts{$user}\n";
|
||||
}
|
||||
my $other = poll_variables($MYSQL_VARIABLES,"Threads_connected") - $total;
|
||||
print "other.value $other\n";
|
||||
}
|
||||
|
||||
sub poll_variables {
|
||||
my $command = shift;
|
||||
my $expression = shift;
|
||||
my $ret = 0;
|
||||
open(SERVICE, "$command |")
|
||||
or die("Coult not execute '$command': $!");
|
||||
while (<SERVICE>) {
|
||||
my ($field, $value) = (m/(\w+).*?(\d+(?:\.\d+)?)/);
|
||||
next unless ($field);
|
||||
if ($field eq $expression ) {
|
||||
$ret = "$value";
|
||||
}
|
||||
}
|
||||
close(SERVICE);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
sub print_graph_information {
|
||||
print <<EOM;
|
||||
graph_title MySQL Connections per user
|
||||
graph_args --base 1000 --lower-limit 0
|
||||
graph_vlabel Connections
|
||||
graph_info The number of current connexions per user.
|
||||
graph_category mysql
|
||||
graph_total Total
|
||||
EOM
|
||||
|
||||
my $counts = count_thread_users();
|
||||
my %counts = %{$counts};
|
||||
my $stacked = 0;
|
||||
|
||||
sub valsort {
|
||||
return $counts{$a} <=> $counts{$b};
|
||||
}
|
||||
my $i = 0;
|
||||
foreach my $user (sort valsort keys(%counts)) {
|
||||
last if $i++ >= $numusers;
|
||||
print <<EOM;
|
||||
$user.label $user
|
||||
$user.info Number of connexions used by user $user
|
||||
EOM
|
||||
print "$user.draw ";
|
||||
# if we already printed an entry, make the next ones stacked
|
||||
if ($i > 1) {
|
||||
print "STACK\n";
|
||||
}
|
||||
else {
|
||||
print "AREA\n";
|
||||
}
|
||||
}
|
||||
|
||||
print <<EOM;
|
||||
other.label Others
|
||||
other.draw STACK
|
||||
other.info Other connected threads not in the top $numusers
|
||||
EOM
|
||||
}
|
||||
|
||||
sub count_thread_users {
|
||||
my %counts = ();
|
||||
my $command = 'mysql -N -B -e "SHOW PROCESSLIST;"';
|
||||
open(SERVICE, "$command |")
|
||||
or die("Could not execute '$command': $!");
|
||||
while (<SERVICE>) {
|
||||
my ($threadid, $user) = split "\t";
|
||||
next unless ($threadid);
|
||||
$counts{$user} = 0 unless defined($counts{$user});
|
||||
$counts{$user}++;
|
||||
}
|
||||
return \%counts;
|
||||
}
|
||||
|
||||
sub test_service {
|
||||
my $return = 1;
|
||||
system ("$MYSQLADMIN --version >/dev/null 2>/dev/null");
|
||||
if ($? == 0)
|
||||
{
|
||||
system ("$TEST_COMMAND >/dev/null 2>/dev/null");
|
||||
if ($? == 0)
|
||||
{
|
||||
print "yes\n";
|
||||
$return = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
print "no (could not connect to mysql)\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
print "no (mysqladmin not found)\n";
|
||||
}
|
||||
exit $return;
|
||||
}
|
144
plugins/network/netatalk3
Executable file
144
plugins/network/netatalk3
Executable file
@ -0,0 +1,144 @@
|
||||
#!/bin/bash -
|
||||
#
|
||||
#### Abstract ################################################################
|
||||
#
|
||||
# Munin contributed plugin to measure open, locked and files being hold by
|
||||
# Netatalk version 3.*;
|
||||
#
|
||||
#### Author ##################################################################
|
||||
#
|
||||
# Otavio Fernandes <otaviof@gmail.com>
|
||||
# Wednesday, 01/01/2014
|
||||
#
|
||||
|
||||
#### Functions ###############################################################
|
||||
#
|
||||
|
||||
function afpd_full_path () {
|
||||
echo $(which afpd |head -n 1)
|
||||
}
|
||||
|
||||
function afp_related_file_exists () {
|
||||
local afp_file_path=$1
|
||||
if [ -z "$afp_file_path" -o ! -f "$afp_file_path" ]; then
|
||||
echo "ERROR: AFP related file not found: \"${afpd_bin_path}\";" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function is_netatalk_version_3 () {
|
||||
local afpd_bin_path=$1
|
||||
version_string="$(${afpd_bin_path} -version |head -n1 |grep '^afpd' |cut -d' ' -f2)"
|
||||
if [[ $version_string != 3\.* ]]; then
|
||||
cat <<EOM >&2
|
||||
ERROR: Netatalk is not version 3.
|
||||
Binary: ${afpd_bin_path};
|
||||
Version: ${version_string};
|
||||
EOM
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function count_running_procs () {
|
||||
local afpd_bin_path=$1
|
||||
echo $(ps ax --no-headers -o command |grep "^${afpd_bin_path}" |wc -l)
|
||||
}
|
||||
|
||||
function count_connected_users () {
|
||||
local afpd_bin_path=$1
|
||||
afpd_procs=$(ps anx --no-headers -o uid,command |grep -E "\w+\d+*\s${afpd_bin_path}" |wc -l)
|
||||
# one of those processess will be always from root user, so it's not being
|
||||
# used to externaly connect volumes, therefor being disconsider.
|
||||
echo $(echo "${afpd_procs} - 1" |bc)
|
||||
}
|
||||
|
||||
function base_lsof () {
|
||||
local afpd_bin_path=$1
|
||||
process_name="$(basename ${afpd_bin_path})"
|
||||
excluded_fds="^DEL,^err,^jld,^ltx,^Mxx,^m86,^mem,^mmap,^pd,^rtd,^tr,^txt,^v86"
|
||||
echo "lsof -a -c ${process_name} -d ${excluded_fds}"
|
||||
}
|
||||
|
||||
function count_locked_files () {
|
||||
local afpd_bin_path=$1
|
||||
cmd_suffix="$(base_lsof "${afpd_bin_path}")"
|
||||
echo "$(${cmd_suffix} -F -l |grep '^l[rRwWu]' |wc -l)"
|
||||
}
|
||||
|
||||
function probe_afp_conf_file () {
|
||||
local afpd_bin_path=$1
|
||||
echo "$(${afpd_bin_path} -version 2>&1 |grep -E '^\s+afp.conf\:' |awk '{print $2}')"
|
||||
}
|
||||
|
||||
function count_open_shares () {
|
||||
local afpd_bin_path=$1
|
||||
local afp_conf_path=$2
|
||||
|
||||
mounted=0
|
||||
declare -a shares=($(grep '^path.*\=' ${afp_conf_path} |awk -F '=' '{print $2}' |sed -E 's/^\s+//g'))
|
||||
if [ ! -z "$shares" ]; then
|
||||
# narrowing lsof results to only list configured mount directories
|
||||
cmd_lookup_prefix=$(echo ${shares[@]} |tr " " "|")
|
||||
cmd_suffix="$(base_lsof "${afpd_bin_path}")"
|
||||
mounted=$(${cmd_suffix} -F n |grep '^n' |egrep "(${cmd_lookup_prefix})" |wc -l)
|
||||
fi
|
||||
echo $mounted
|
||||
}
|
||||
|
||||
|
||||
#### Main ####################################################################
|
||||
# For all routines, holds the entry points dealing with the informed parameter
|
||||
# or lack of it, meaning just print out collected data.
|
||||
#
|
||||
|
||||
case "$1" in
|
||||
config)
|
||||
# printing configuration for this plugin's produced data
|
||||
cat <<EOM
|
||||
graph_title Netatalk v3 Status
|
||||
graph_title Netatalk status
|
||||
graph_args --logarithmic --lower-limit 0.1
|
||||
graph_vlabel Number
|
||||
graph_category network
|
||||
proc.label Running processes
|
||||
proc.info Running AFPd processes
|
||||
proc.min 0
|
||||
user.label Connected users
|
||||
user.info Connected users
|
||||
user.min 0
|
||||
lock.label Locked files
|
||||
lock.info AFPd locked files
|
||||
lock.min 0
|
||||
share.label Open shares
|
||||
share.info Netatalk open shares
|
||||
share.min 0
|
||||
EOM
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
#### Boilerplates ####################################################
|
||||
# Locating AFP related files:
|
||||
# * Binary: Using the first result of "which" command;
|
||||
# * Config: Using "afpd" with paremeters to pring configuration file
|
||||
# location;
|
||||
#
|
||||
|
||||
AFPD_PATH="$(afpd_full_path)"
|
||||
afp_related_file_exists "${AFPD_PATH}"
|
||||
is_netatalk_version_3 "${AFPD_PATH}"
|
||||
|
||||
AFP_CONF_PATH="$(probe_afp_conf_file "${AFPD_PATH}")"
|
||||
afp_related_file_exists "${AFP_CONF_PATH}"
|
||||
|
||||
#### Collecting Metrics ##############################################
|
||||
#
|
||||
echo "proc.value" $(count_running_procs "${AFPD_PATH}")
|
||||
echo "user.value" $(count_connected_users "${AFPD_PATH}")
|
||||
echo "lock.value" $(count_locked_files "${AFPD_PATH}")
|
||||
echo "share.value" $(count_open_shares "${AFPD_PATH}" "${AFP_CONF_PATH}")
|
||||
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
# EOF
|
@ -25,7 +25,7 @@
|
||||
# Use it in your site configuration (/etc/nginx/sites-enabled/anything.conf):
|
||||
# access_log /var/log/nginx/upstream.log upstream;
|
||||
#
|
||||
# And specify some options in munin-node.conf:
|
||||
# And specify some options in /etc/munin/plugin-conf.d/munin-node:
|
||||
#
|
||||
# [nginx_upstream_multi_upstream]
|
||||
# env.graphs cache http time request
|
||||
|
187
plugins/snmp/snmp__juniper
Executable file
187
plugins/snmp/snmp__juniper
Executable file
@ -0,0 +1,187 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2014 Johann Schmitz <johann@j-schmitz.net>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Library General Public License as published by
|
||||
# the Free Software Foundation; version 2 only
|
||||
#
|
||||
# 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 Library General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Library 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.
|
||||
#
|
||||
|
||||
"""
|
||||
=head1 NAME
|
||||
|
||||
snmp__juniper - Health monitoring plugin for Juniper firewalls.
|
||||
|
||||
=head1 CONFIGURATION
|
||||
|
||||
Make sure your Juniper device is accessible via SNMP (e.g. via snmpwalk) and the munin-node
|
||||
has been configured correctly.
|
||||
|
||||
=head1 MAGIC MARKERS
|
||||
|
||||
#%# family=snmpauto
|
||||
#%# capabilities=snmpconf
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
0.0.1
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
Open a ticket at https://github.com/ercpe/contrib if you find one.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Johann Schmitz <johann@j-schmitz.net>
|
||||
|
||||
=head1 LICENSE
|
||||
|
||||
GPLv2
|
||||
|
||||
=cut
|
||||
"""
|
||||
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
import logging
|
||||
|
||||
from pysnmp.entity.rfc3413.oneliner import cmdgen
|
||||
|
||||
host = None
|
||||
port = os.getenv('port', 161)
|
||||
community = os.getenv('community', None)
|
||||
|
||||
debug = bool(os.getenv('MUNIN_DEBUG', os.getenv('DEBUG', 0)))
|
||||
|
||||
if debug:
|
||||
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)-7s %(message)s')
|
||||
|
||||
try:
|
||||
match = re.search("^(?:|.*\/)snmp_([^_]+)_juniper$", sys.argv[0])
|
||||
host = match.group(1)
|
||||
request = match.group(2)
|
||||
match = re.search("^([^:]+):(\d+)$", host)
|
||||
if match is not None:
|
||||
host = match.group(1)
|
||||
port = match.group(2)
|
||||
except:
|
||||
pass
|
||||
|
||||
jnxOperatingTable = '1.3.6.1.4.1.2636.3.1.13.1.5'
|
||||
|
||||
jnxOperatingTemp = '1.3.6.1.4.1.2636.3.1.13.1.7'
|
||||
jnxOperatingCPU = '1.3.6.1.4.1.2636.3.1.13.1.8'
|
||||
jnxOperatingBuffer = '1.3.6.1.4.1.2636.3.1.13.1.11'
|
||||
|
||||
class JunOSSnmpClient(object):
|
||||
def __init__(self, host, port, community):
|
||||
self.hostname = host
|
||||
self.transport = cmdgen.UdpTransportTarget((host, int(port)))
|
||||
self.auth = cmdgen.CommunityData('test-agent', community)
|
||||
self.gen = cmdgen.CommandGenerator()
|
||||
|
||||
def get_devices(self):
|
||||
errorIndication, errorStatus, errorIndex, varBindTable = self.gen.bulkCmd(
|
||||
self.auth,
|
||||
self.transport,
|
||||
0, 20,
|
||||
jnxOperatingTable)
|
||||
# ignoreNonIncreasingOids=True) # only available with pysnmp >= 4.2.4 (?)
|
||||
|
||||
if errorIndication:
|
||||
logging.error("SNMP bulkCmd for devices failed: %s, %s, %s" % (errorIndication, errorStatus, errorIndex))
|
||||
return {}
|
||||
|
||||
devices = {}
|
||||
for row in varBindTable:
|
||||
for name, value in row:
|
||||
if not str(name).startswith(jnxOperatingTable):
|
||||
continue
|
||||
|
||||
# TODO: Find a better way to get the routing engines in a cluster
|
||||
if str(value).endswith(' Routing Engine'):
|
||||
devices[str(name)[len(jnxOperatingTable):]] = re.sub("[^\w]", '_', str(value).replace(' Routing Engine', ''))
|
||||
return devices
|
||||
|
||||
def get_one(self, prefix_oid, suffix):
|
||||
oid = prefix_oid + suffix
|
||||
errorIndication, errorStatus, errorIndex, varBindTable = self.gen.getCmd(
|
||||
self.auth,
|
||||
self.transport,
|
||||
oid)
|
||||
|
||||
if errorIndication:
|
||||
logging.error("SNMP getCmd for %s failed: %s, %s, %s" % (oid, errorIndication, errorStatus, errorIndex))
|
||||
return None
|
||||
|
||||
return int(varBindTable[0][1])
|
||||
|
||||
|
||||
|
||||
def get_data(self):
|
||||
devs = self.get_devices()
|
||||
|
||||
return {
|
||||
'temp': dict([(name, self.get_one(jnxOperatingTemp, suffix)) for suffix, name in devs.iteritems()]),
|
||||
'cpu': dict([(name, self.get_one(jnxOperatingCPU, suffix)) for suffix, name in devs.iteritems()]),
|
||||
'buffer': dict([(name, self.get_one(jnxOperatingBuffer, suffix)) for suffix, name in devs.iteritems()]),
|
||||
}
|
||||
|
||||
def print_config(self):
|
||||
devices = self.get_devices()
|
||||
|
||||
data_def = [
|
||||
('temp', self.hostname, 'System temperature', '--base 1000', 'System temperature in C', 'system'),
|
||||
('cpu', self.hostname, 'CPU usage', '--base 1000 -l 0 --upper-limit 100', 'CPU usage in %', 'system'),
|
||||
('buffer', self.hostname, 'Buffer usage', '--base 1000 -l 0 --upper-limit 100', 'Buffer usage in %', 'system'),
|
||||
]
|
||||
|
||||
for datarow, hostname, title, args, vlabel, category in data_def:
|
||||
print """multigraph juniper_{datarow}
|
||||
host_name {hostname}
|
||||
graph_title {title}
|
||||
graph_vlabel {vlabel}
|
||||
graph_args {args}
|
||||
graph_category {category}
|
||||
graph_info {title}""".format(datarow=datarow, hostname=hostname, title=title, args=args, vlabel=vlabel, category=category)
|
||||
|
||||
for suffix, node in devices.iteritems():
|
||||
ident = "%s_%s" % (datarow, node)
|
||||
print """{label}.info {title} on {node}
|
||||
{label}.label {node}
|
||||
{label}.type GAUGE
|
||||
{label}.min 0""".format(title=title, label=ident, node=node)
|
||||
|
||||
def execute(self):
|
||||
data = self.get_data()
|
||||
|
||||
for pre, values in data.iteritems():
|
||||
print "multigraph juniper_%s" % pre
|
||||
for node, value in values.iteritems():
|
||||
print "%s_%s.value %s" % (pre, node, value)
|
||||
|
||||
c = JunOSSnmpClient(host, port, community)
|
||||
|
||||
if "snmpconf" in sys.argv[1:]:
|
||||
print "require 1.3.6.1.4.1.2636.3.1.13.1.5"
|
||||
sys.exit(0)
|
||||
else:
|
||||
if not (host and port and community):
|
||||
print "# Bad configuration. Cannot run with Host=%s, port=%s and community=%s" % (host, port, community)
|
||||
sys.exit(1)
|
||||
|
||||
if "config" in sys.argv[1:]:
|
||||
c.print_config()
|
||||
else:
|
||||
c.execute()
|
229
plugins/snmp/snmp__juniper_spu
Executable file
229
plugins/snmp/snmp__juniper_spu
Executable file
@ -0,0 +1,229 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2014 Johann Schmitz <johann@j-schmitz.net>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Library General Public License as published by
|
||||
# the Free Software Foundation; version 2 only
|
||||
#
|
||||
# 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 Library General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Library 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.
|
||||
#
|
||||
|
||||
"""
|
||||
=head1 NAME
|
||||
|
||||
snmp__juniper_spu - Network monitoring plugin for the SPU's in Juniper firewalls.
|
||||
|
||||
=head1 CONFIGURATION
|
||||
|
||||
Make sure your Juniper device is accessible via SNMP (e.g. via snmpwalk) and the munin-node
|
||||
has been configured correctly.
|
||||
|
||||
=head1 MAGIC MARKERS
|
||||
|
||||
#%# family=snmpauto
|
||||
#%# capabilities=snmpconf
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
0.0.1
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
Open a ticket at https://github.com/ercpe/contrib if you find one.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Johann Schmitz <johann@j-schmitz.net>
|
||||
|
||||
=head1 LICENSE
|
||||
|
||||
GPLv2
|
||||
|
||||
=cut
|
||||
"""
|
||||
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
import logging
|
||||
|
||||
from pysnmp.entity.rfc3413.oneliner import cmdgen
|
||||
|
||||
host = None
|
||||
port = os.getenv('port', 161)
|
||||
community = os.getenv('community', "public")
|
||||
|
||||
debug = bool(os.getenv('MUNIN_DEBUG', os.getenv('DEBUG', 0)))
|
||||
|
||||
if debug:
|
||||
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)-7s %(message)s')
|
||||
|
||||
try:
|
||||
match = re.search("^(?:|.*\/)snmp_([^_]+)_juniper_spu$", sys.argv[0])
|
||||
host = match.group(1)
|
||||
request = match.group(2)
|
||||
match = re.search("^([^:]+):(\d+)$", host)
|
||||
if match is not None:
|
||||
host = match.group(1)
|
||||
port = match.group(2)
|
||||
except:
|
||||
pass
|
||||
|
||||
jnxJsSPUMonitoringObjectsTable = '1.3.6.1.4.1.2636.3.39.1.12.1.1'
|
||||
#jnxJsSPUMonitoringIndex = jnxJsSPUMonitoringObjectsTable + '.1.1'
|
||||
#jnxJsSPUMonitoringFPCIndex = jnxJsSPUMonitoringObjectsTable + '.1.2'
|
||||
#jnxJsSPUMonitoringSPUIndex = jnxJsSPUMonitoringObjectsTable + '.1.3'
|
||||
#jnxJsSPUMonitoringCPUUsage = jnxJsSPUMonitoringObjectsTable + '.1.4'
|
||||
#jnxJsSPUMonitoringMemoryUsage = jnxJsSPUMonitoringObjectsTable + '.1.5'
|
||||
jnxJsSPUMonitoringCurrentFlowSession = jnxJsSPUMonitoringObjectsTable + '.1.6'
|
||||
jnxJsSPUMonitoringMaxFlowSession = jnxJsSPUMonitoringObjectsTable + '.1.7'
|
||||
jnxJsSPUMonitoringCurrentCPSession = jnxJsSPUMonitoringObjectsTable + '.1.8'
|
||||
jnxJsSPUMonitoringMaxCPSession = jnxJsSPUMonitoringObjectsTable + '.1.9'
|
||||
#jnxJsSPUMonitoringNodeIndex = jnxJsSPUMonitoringObjectsTable + '.1.10'
|
||||
jnxJsSPUMonitoringNodeDescr = jnxJsSPUMonitoringObjectsTable + '.1.11'
|
||||
jnxJsSPUMonitoringFlowSessIPv4 = jnxJsSPUMonitoringObjectsTable + '.1.12'
|
||||
jnxJsSPUMonitoringFlowSessIPv6 = jnxJsSPUMonitoringObjectsTable + '.1.13'
|
||||
jnxJsSPUMonitoringCPSessIPv4 = jnxJsSPUMonitoringObjectsTable + '.1.14'
|
||||
jnxJsSPUMonitoringCPSessIPv6 = jnxJsSPUMonitoringObjectsTable + '.1.15'
|
||||
|
||||
class JunOSSnmpClient(object):
|
||||
|
||||
def __init__(self, host, port, community):
|
||||
self.hostname = host
|
||||
self.transport = cmdgen.UdpTransportTarget((host, int(port)))
|
||||
self.auth = cmdgen.CommunityData('test-agent', community)
|
||||
self.gen = cmdgen.CommandGenerator()
|
||||
|
||||
def get_data(self):
|
||||
errorIndication, errorStatus, errorIndex, varBindTable = self.gen.bulkCmd(
|
||||
self.auth,
|
||||
self.transport,
|
||||
0, 10,
|
||||
jnxJsSPUMonitoringObjectsTable)
|
||||
# ignoreNonIncreasingOids=True) # only available with pysnmp >= 4.2.4 (?) and broken anyway
|
||||
|
||||
if errorIndication:
|
||||
logging.error("SNMP bulkCmd for devices failed: %s, %s, %s" % (errorIndication, errorStatus, errorIndex))
|
||||
return {}
|
||||
|
||||
devices = {}
|
||||
values = {}
|
||||
for row in varBindTable:
|
||||
for name, value in row:
|
||||
if not str(name).startswith(jnxJsSPUMonitoringObjectsTable):
|
||||
continue
|
||||
|
||||
oid = str(name)
|
||||
|
||||
nodeid = oid[oid.rindex('.'):]
|
||||
|
||||
idx = oid[len(jnxJsSPUMonitoringObjectsTable)+3:]
|
||||
idx = idx[:idx.index('.')]
|
||||
|
||||
if oid.startswith(jnxJsSPUMonitoringNodeDescr):
|
||||
devices[nodeid] = str(value)
|
||||
continue
|
||||
|
||||
values[oid] = int(value)
|
||||
return devices, values
|
||||
|
||||
def print_config(self):
|
||||
devices, data = self.get_data()
|
||||
|
||||
data_def = [
|
||||
('flow', self.hostname, 'Flow sessions', '--base 1000', '# of sessions', jnxJsSPUMonitoringMaxFlowSession),
|
||||
('cp', self.hostname, 'Central point sessions', '--base 1000', '# of sessions', jnxJsSPUMonitoringMaxCPSession),
|
||||
]
|
||||
|
||||
for datarow, hostname, title, args, vlabel, max_prefix in data_def:
|
||||
print """multigraph juniper_{datarow}
|
||||
host_name {hostname}
|
||||
graph_title {title}
|
||||
graph_vlabel {vlabel}
|
||||
graph_args {args}
|
||||
graph_category network
|
||||
graph_info {title}""".format(datarow=datarow, hostname=hostname, title=title, args=args, vlabel=vlabel)
|
||||
|
||||
for suffix, node in devices.iteritems():
|
||||
ident = "%s_%s" % (datarow, node)
|
||||
print """{label}.info {title} on {node}
|
||||
{label}.label {node}
|
||||
{label}.type GAUGE
|
||||
{label}.max {max}""".format(title=title, label=ident, node=node, max=data.get(max_prefix + suffix))
|
||||
|
||||
for suffix, node in devices.iteritems():
|
||||
print """
|
||||
multigraph juniper_{datarow}.{node}
|
||||
host_name {hostname}
|
||||
graph_title {title} on {node}
|
||||
graph_vlabel {vlabel}
|
||||
graph_args {args}
|
||||
graph_category network
|
||||
graph_info {title}
|
||||
{datarow}V4.info Current IPv4 {datarow} sessions
|
||||
{datarow}V4.label IPv4
|
||||
{datarow}V4.draw AREASTACK
|
||||
{datarow}V4.type GAUGE
|
||||
{datarow}V6.info Current IPv6 {datarow} sessions
|
||||
{datarow}V6.label IPv6
|
||||
{datarow}V6.draw AREASTACK
|
||||
{datarow}V6.type GAUGE
|
||||
{datarow}Current.info Current total {datarow} sessions
|
||||
{datarow}Current.label Total
|
||||
{datarow}Current.draw LINE1
|
||||
{datarow}Current.type GAUGE
|
||||
{datarow}Current.colour 000000
|
||||
{datarow}Max.info Max. {datarow} sessions supported by the device(s)
|
||||
{datarow}Max.label Max
|
||||
{datarow}Max.draw LINE0
|
||||
{datarow}Max.type GAUGE
|
||||
""".format(datarow=datarow, hostname=hostname, title=title, args=args, vlabel=vlabel, node=node)
|
||||
|
||||
def execute(self):
|
||||
devices, data = self.get_data()
|
||||
|
||||
print "multigraph juniper_flow"
|
||||
for suffix, node in devices.iteritems():
|
||||
print "flow_%s.value %s" % (node, data.get(jnxJsSPUMonitoringCurrentFlowSession + suffix, 0))
|
||||
|
||||
for suffix, node in devices.iteritems():
|
||||
print "multigraph juniper_flow.%s" % node
|
||||
print "flowV4.value %s" % data.get(jnxJsSPUMonitoringFlowSessIPv4 + suffix, 0)
|
||||
print "flowV6.value %s" % data.get(jnxJsSPUMonitoringFlowSessIPv6 + suffix, 0)
|
||||
print "flowCurrent.value %s" % data.get(jnxJsSPUMonitoringCurrentFlowSession + suffix, 0)
|
||||
print "flowMax.value %s" % data.get(jnxJsSPUMonitoringMaxFlowSession + suffix, 0)
|
||||
|
||||
print "multigraph juniper_cp"
|
||||
for suffix, node in devices.iteritems():
|
||||
print "cp_%s.value %s" % (node, data.get(jnxJsSPUMonitoringCurrentCPSession + suffix, 0))
|
||||
|
||||
for suffix, node in devices.iteritems():
|
||||
print "multigraph juniper_cp.%s" % node
|
||||
print "cpV4.value %s" % data.get(jnxJsSPUMonitoringCPSessIPv4 + suffix, 0)
|
||||
print "cpV6.value %s" % data.get(jnxJsSPUMonitoringCPSessIPv6 + suffix, 0)
|
||||
print "cpCurrent.value %s" % data.get(jnxJsSPUMonitoringCurrentCPSession + suffix, 0)
|
||||
print "cpMax.value %s" % data.get(jnxJsSPUMonitoringMaxCPSession + suffix, 0)
|
||||
|
||||
c = JunOSSnmpClient(host, port, community)
|
||||
|
||||
if "snmpconf" in sys.argv[1:]:
|
||||
print "require %s" % (jnxJsSPUMonitoringObjectsTable, )
|
||||
sys.exit(0)
|
||||
else:
|
||||
if not (host and port and community):
|
||||
print "# Bad configuration. Cannot run with Host=%s, port=%s and community=%s" % (host, port, community)
|
||||
sys.exit(1)
|
||||
|
||||
if "config" in sys.argv[1:]:
|
||||
c.print_config()
|
||||
else:
|
||||
c.execute()
|
@ -54,6 +54,9 @@ if (!file_exists($sTmpFilePath)) {
|
||||
fclose($fp);
|
||||
|
||||
$toShow = (int) ($iCurrent - (int) $iOldCount);
|
||||
if ($toShow < 0) {
|
||||
$toShow = 0;
|
||||
}
|
||||
}
|
||||
|
||||
echo "current.value $toShow\n";
|
||||
|
@ -54,6 +54,9 @@ if (!file_exists($sTmpFilePath)) {
|
||||
fclose($fp);
|
||||
|
||||
$toShow = (int) ($iCurrent - (int) $iOldCount);
|
||||
if ($toShow < 0) {
|
||||
$toShow = 0;
|
||||
}
|
||||
}
|
||||
|
||||
echo "current.value $toShow\n";
|
||||
|
@ -6,10 +6,12 @@
|
||||
#%# capabilities=autoconf
|
||||
|
||||
sysctl='/sbin/sysctl'
|
||||
ostype=`uname -s`
|
||||
procfile='/proc/spl/kstat/zfs/arcstats'
|
||||
|
||||
case $1 in
|
||||
config)
|
||||
cat <<EOF
|
||||
cat <<EOF
|
||||
graph_title ZFS ARC efficiency
|
||||
graph_vlabel %
|
||||
graph_scale no
|
||||
@ -209,23 +211,37 @@ EOF
|
||||
# mru_ghost_hits_perc.cdef mru_ghost_hits,100,*,hits,/
|
||||
# mru_ghost_hits_perc.label Most recently used ghost hits
|
||||
# mru_ghost_hits_perc.graph no
|
||||
exit 0
|
||||
;;
|
||||
exit 0
|
||||
;;
|
||||
autoconf)
|
||||
if [ ! -x ${sysctl} ]; then
|
||||
echo "no (${sysctl} is not executable)"
|
||||
exit 1
|
||||
fi
|
||||
ostype=`uname -s`
|
||||
if [ ${ostype} = "FreeBSD" ]; then
|
||||
echo "yes"
|
||||
exit 0
|
||||
fi
|
||||
echo "no (You're OS is not supported by this plugin)"
|
||||
exit 1
|
||||
;;
|
||||
if [ ! -x ${sysctl} ]; then
|
||||
echo "no (${sysctl} is not executable)"
|
||||
exit 1
|
||||
fi
|
||||
if [ ${ostype} = "FreeBSD" ]; then
|
||||
echo "yes"
|
||||
exit 0
|
||||
fi
|
||||
if [ ${ostype} = "Linux" ]; then
|
||||
if [ -f ${procfile} ]; then
|
||||
echo "yes"
|
||||
exit 0
|
||||
fi
|
||||
echo "no (The statsfile does not exist: ${procfile})"
|
||||
exit 1
|
||||
fi
|
||||
echo "no (You're OS is not supported by this plugin)"
|
||||
exit 1
|
||||
;;
|
||||
suggest)
|
||||
exit 0
|
||||
;;
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
case ${ostype} in
|
||||
"FreeBSD")
|
||||
$sysctl kstat.zfs.misc.arcstats | sed -e 's/^kstat.zfs.misc.arcstats.//' -e 's/:/.value/'
|
||||
;;
|
||||
"Linux")
|
||||
cat ${procfile} | tail -n +3 | sed -e 's/ \+/ /g' | cut -f 1,3 -d ' ' | sed -e 's/ /.value /'
|
||||
;;
|
||||
esac
|
||||
$sysctl kstat.zfs.misc.arcstats | sed -e 's/^kstat.zfs.misc.arcstats.//' -e 's/:/.value/'
|
||||
|
Loading…
Reference in New Issue
Block a user