2
0
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:
Clemens Schwaighofer 2014-02-04 17:17:33 +09:00
commit 54dee0ad42
14 changed files with 1204 additions and 46 deletions

View File

@ -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
View 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

View File

@ -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)

View File

@ -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);

View File

@ -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
View 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

View 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
View 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

View File

@ -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
View 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
View 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()

View File

@ -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";

View File

@ -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";

View File

@ -6,6 +6,8 @@
#%# capabilities=autoconf
sysctl='/sbin/sysctl'
ostype=`uname -s`
procfile='/proc/spl/kstat/zfs/arcstats'
case $1 in
config)
@ -216,11 +218,18 @@ EOF
echo "no (${sysctl} is not executable)"
exit 1
fi
ostype=`uname -s`
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
;;
@ -228,4 +237,11 @@ EOF
exit 0
;;
esac
$sysctl kstat.zfs.misc.arcstats | sed -e 's/^kstat.zfs.misc.arcstats.//' -e 's/:/.value/'
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