Plugin freeradius_sqlippool_: New plugin to show IP pool utilisation

Uses the generic Perl DBI interface, requiring the user to specify a driver and
provide the corresponding DBD module
This commit is contained in:
Terry Burton 2020-02-17 12:40:39 +00:00 committed by Lars Kruse
parent 937cb1d030
commit 06cfee0689
1 changed files with 203 additions and 0 deletions

View File

@ -0,0 +1,203 @@
#!/usr/bin/perl -w
# -*- perl -*-
use strict;
=head1 NAME
freeradius_sqlippools_ - Plugin to monitor IP pool utilisation
=head1 CONFIGURATION
This is a wildcard plugin to support fetching the status of multiple sqlippool
instances.
It can also be linked directly (as with a non-wildcard plugin) to present a
combined graph showing the percentage utilisation of all pools.
It is likely that a common configuration will apply to all plugins but this
doesn't have to be so:
[freeradius_sqlippools_*]
env.fr_driver mysql
env.fr_host 192.0.2.1
env.fr_port 3306
env.fr_db radius
env.fr_user radius
env.fr_pass radpass
fr_driver is the name of the Perl DBI driver used in the DSN connection string.
The corresponding DBD module for the driver must be installed.
You should omit fr_pass and specify fr_passfile to avoid placing the password
in a plugin configuration file that is world accessible, e.g.:
[freeradius_sqlippools_mypool]
user radmonitor
group radmonitor
env.fr_driver Pg
env.fr_host 192.0.2.2
env.fr_port 5432
env.fr_db radius
env.fr_user radmonitor
env.fr_passfile /home/radmonitor/db_pass.txt
=head1 AUTHORS
Original Author: Network RADIUS
=head1 LICENSE
GPLv2
=head1 MAGIC MARKERS
#%# family=auto
#%# capabilities=autoconf suggest
=cut
use File::Basename;
use Storable qw(lock_store lock_retrieve);
use DBI;
use constant STATEFILE => "$ENV{MUNIN_PLUGSTATE}/freeradius_sqlippools.state";
use constant SQL => <<'EOF';
SELECT
DISTINCT pool_name AS pool_name,
COUNT(id) OVER (PARTITION BY pool_name) AS total,
SUM(CASE WHEN expiry_time > NOW() THEN 1 ELSE 0 END) OVER (PARTITION BY pool_name) AS used
FROM radippool
EOF
my $script = basename($0);
(my $instance) = $script =~ /freeradius_sqlippools_(.+)/;
my $command = $ARGV[0] || 'show';
autoconf() if $command eq 'autoconf';
suggest() if $command eq 'suggest';
config_instance($instance) if $command eq 'config' && defined $instance;
config_combined() if $command eq 'config' && !defined $instance;
show_instance($instance) if $command eq 'show' && defined $instance;
show_combined() if $command eq 'show' && !defined $instance;
exit;
sub autoconf {
my $results;
eval {
$results = get_pools(1);
};
if ($results) {
print "yes\n";
} else {
print "no (Failed to read pool status from database)\n";
}
}
sub suggest {
my $pools = get_pools(1);
return unless defined $pools;
print "$_\n" foreach keys %{$pools};
}
sub config_instance {
my $instance = shift;
print <<EOF;
graph_title FreeRADIUS SQL IP pool ($instance)
graph_category Other
graph_args -l 0
total.label Total IPs
total.draw AREA
used.label Allocated IPs
used.draw AREA
EOF
}
sub config_combined {
print <<EOF;
graph_title FreeRADIUS SQL IP pools
graph_category Other
graph_args -l 0 -u 100
graph_vlabel Utilisation (%)
EOF
my $pools = get_pools();
foreach (keys %{$pools}) {
print "$_.label Pool: $_\n";
print "$_.warning 90\n";
print "$_.critical 95\n";
}
}
sub show_instance {
my $instance = shift;
my $pool = get_pools()->{$instance};
print "total.value $pool->{total}\n";
print "used.value $pool->{used}\n";
}
sub show_combined {
my $pools = get_pools();
foreach (keys %{$pools}) {
my $util = $pools->{$_}->{used} * 100 / $pools->{$_}->{total};
print "$_.value $util\n";
}
}
sub get_pools {
my $no_cache = shift; # Ensure that caching doesn't interfere with reconfiguration
# Read results from the cache unless stale or told not to
if (!$no_cache && -e STATEFILE && -M STATEFILE < 60/86400) {
return lock_retrieve(STATEFILE);
}
my $driver = $ENV{'fr_driver'} || 'mysql';
my $host = $ENV{'fr_host'} || '127.0.0.1';
my $port = $ENV{'fr_port'} || '3306';
my $db = $ENV{'fr_db'} || 'radius';
my $user = $ENV{'fr_user'} || 'radius';
my $pass = $ENV{'fr_pass'} || 'radpass';
my $passfile = $ENV{'fr_passfile'};
# Read password from a file
if (!defined $pass && defined $passfile) {
open (my $FH, '<', $passfile) || die "Failed to open fr_passfile: $passfile";
$pass = <$FH>;
chomp $pass;
close $FH;
}
my $dsn;
if ($driver eq 'Oracle') {
$dsn = "DBI:$driver:$db";
} else {
$dsn = "DBI:$driver:database=$db;host=$host";
}
$dsn .= ";port=$port" if $port;
# Read the results by running our query against the database
my $dbh = DBI->connect($dsn, $user, $pass, { RaiseError => 1, PrintError => 0, AutoCommit => 1 });
my $sth = $dbh->prepare(SQL);
$sth->execute();
my $results=$sth->fetchall_hashref('pool_name');
$sth->finish();
$dbh->disconnect();
# Cache the results
if (!$no_cache && $results) {
lock_store($results,STATEFILE);
}
return $results;
}
# vim:syntax=perl