#!/usr/bin/perl # =head1 NAME quota_usage_ - Plugin to monitor quota on a specified device. =head1 APPLICABLE SYSTEMS Needs repquota and root privs =head1 USAGE Create Service Link /etc/munin/plugins/quota_usage_ for example C. Use underscores instead of slashes, for example to monitor C, name this C For backwards compatibility the prefix C is also acceptable (instead of C). This plugin uses the soft and hard quota data for warning and critical levels respectively. =head1 MAGIC MARKERS #%# family=manual =head1 AUTHOR Unknown author Source: L L =head1 LICENSE GPLv2 =cut use strict; use warnings; use Munin::Plugin; use File::Spec::Functions qw(splitdir); # We do some magic to allow device strings with underscore to mean a / # So to monitor /dev/mapper/vol-foo use "quota_usage_mapper_vol-foo" or # "quota-usage_mapper_vol-foo". The latter was advertised as the default usage previously, but it # is confusing since it does not match the name of the plugin exactly. # See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=730030 my @path_tokens = splitdir($0); my $basename = $path_tokens[-1]; # partial name of the device (it will be prefixed with "/dev/") my $dev; if ($basename =~ /^quota_usage_(.+)$/) { # The plugin was called with the basename "quota_usage_*". $dev = $1; $dev =~ s#_#/#g; } else { # The plugin was called with the basename "quota-usage_*" (or another prefix without an # underscore). # This approach was documented for this plugin. But it conflicts with the common style of # using the exact plugin name (instead of a slight variation) for symlinks. my @tmp = split(/_/, $basename); shift @tmp; $dev = join("/", @tmp); } my %users; open (REP, "/usr/sbin/repquota /dev/$dev |") or exit 22; while () { chomp; if (/^-+$/../^$/) { my @data = split(/ +/); next if !$data[0] || $data[0] =~ /^#/; if ( @data > 2 && $data[2] > 0 ) { $users{$data[0]}[0] = $data[2]; # current usage $users{$data[0]}[1] = $data[3]; # Soft quota $users{$data[0]}[2] = $data[4]; # Hard quota } } } close REP; my @users_by_usage = sort { $users{$b} <=> $users{$a} } keys(%users); if ($ARGV[0] and $ARGV[0] eq "config") { print "graph_title Filesystem usage by user on $dev\n"; print "graph_args --base 1024 --lower-limit 0\n"; print "graph_vlabel bytes\n"; print "graph_category disk\n"; for my $user (@users_by_usage) { my ($uid, $name) = (getpwnam($user))[2,6]; my $id = clean_fieldname($user); $name = $user if (length($name) < length($user)); $name = (split(/,/, $name))[0]; printf "%s.label %s\n", $id, $name; printf "%s.cdef %s,1024,*\n", $id, $id; if ($users{$user}[1] && $users{$user}[1] > 0) { printf "%s.warning %s\n", $id, $users{$user}[1]; } if ($users{$user}[2] && $users{$user}[2] > 0) { printf "%s.critical %s\n", $id, $users{$user}[2]; } if ($uid < 200) { printf "%s.graph no\n", $id } } } else { for my $user (@users_by_usage) { my $esc = $user; $esc = clean_fieldname($esc); printf "%s.value %s\n", $esc, $users{$user}[0]; } }