diff --git a/plugins/freeradius/freeradius_sqlippools_ b/plugins/freeradius/freeradius_sqlippools_ new file mode 100755 index 00000000..bfaca5b7 --- /dev/null +++ b/plugins/freeradius/freeradius_sqlippools_ @@ -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 <{$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