Freespace check and warning Perl script

Freespace check and warning Perl script

A while back I needed a warning system for when my backups disk runs out of free space. Gathering information from various other existing scripts, I wrote a small Perl script that checks the available space and sends warning emails if this drops below a defined level.

Prerequisites

You need to have Perl installed for the script to run. The installation/configuration steps below are Fedora/CentOS/RedHat systems, but the script should work on any Linux system via Perl.

The script requires the Filesys::DiskFree, File::Touch modules, both installable via CPAN perl -MCPAN -e shell

If you get a Can’t locate CPAN.pm in @INC … then you need to install CPAN first: yum install perl-CPAN -y

First run of CPAN will run some diagnosis test (which may take a while). It’s also a good idea to update CPAN by running the following in the prompt:
install CPAN
reload cpan

Then simply install the required Perl modules (this should be quick) with install Filesys::DiskFree File::Touch

“Installation” and configuration

This script has a couple of configurable parameters that need to be defined for it to work correctly (these are located at the beginning of the script).

Filesystems
$count Number of the mount points defined below
@dirs Comma separated list of mount points to monitor; eg: (“/”,”/backups”)
$work_dirs Temporary directory used by the script to store temporary data. Needs to be writeable by the user running the script.
Warning settings
$warning_level The percentage of free disk space under which the warnings are triggered; default = 10 %
$warning_interval Interval in minutes between warning emails (if level is reached); default = 10 (minutes)
$warning_remind 0 = send warning email once and only warn again when space level decreases again
1 = send warning email every “interval” minutes even if space level no longer decreased
Email settings
$to E-mail address of the recipient (this should be your email)
$from E-mail address used by the script as the sender

 

Finally create a cron entry to run the script (this will check free space on the configured mount points every 10 minutes):

*/10 * * * * /etc/rc.d/freespace.pl >/dev/null 2>&1

Code

Copy-paste the code below into /etc/rc.d/freespace.pl:

#!/usr/bin/perl
# 
# free space warning script
# v0.3 / 20081211
# (c) zedt.eu
# 

use strict;
use warnings;
use Filesys::DiskFree;
use File::Touch;

# ---
# CONFIGURE:

# file systems to monitor
my $count = 2;
my @dirs = ("/","/storage");
my $work_dir = "/etc/freespace2/"; # write access required!

# warning parameters
my $warning_level=10;
my $warning_interval=0; #minutes between mails if warning triggered for a monitored disk
my $warning_remind=0; # 0 sends warning once no matter the interval until space level decreases again
                      # 1 sends email every "interval" even if space level no longer decreases

# email setup
my $to='root@localhost';
my $from='watchdog@localhost';
my $subject='Low Disk Space Warning';
my $out='WARNING! Low Disk Space on:';

# END
# ---
# DO NOT ALTER BEYOND THIS LINE

my $send=0;

for(my $i = 0; $i < $count; $i++) {   	
# get df 	
my $handle = new Filesys::DiskFree; 	
$handle->df();

      # calculate
      my $av = $handle->avail($dirs[$i]);
      my $us = $handle->used($dirs[$i]);
      my $df_free = (($av) / ($av+$us)) * 100.0;

      # compare
      if ($df_free < $warning_level) {

             my $dir = $dirs[$i];
             $dir =~ s/\//_/g;
             my $currfilename = $work_dir.$dir;

             # check if warning already sent
             if (-e $currfilename)

                     {
                     # warning already sent; check if within $warning_interval
                     my @status = stat($currfilename);
                     my $now = time();
                     if (($now)-($status[9]) <($warning_interval-1)*60 )
                               {
                               # interval not reached yet
                               # nothing to do 
                               }
                     else 
                               {
                               # $warning_interval crossed; process statfile and resend warning if set
                               open FILE, "<",$currfilename or die $!;
                               my @lines = <FILE>;
                               close FILE;
                               my $rnd_df_free = sprintf("%0.2f",$df_free); # round up value to
                               my $rnd_lines = sprintf("%0.2f",$lines[0]);  # two decimals numbers
                               if (($rnd_df_free) < ($rnd_lines))  					
                                       { 
                                       # space level has dropped since last check so must send warning                                         
                                       $send = 1;                                         
                                       $out = $out . sprintf("\n > $dirs[$i] (%0.2f%%)",$df_free); 
                                       # update statsfile with new value
                                       open FILE, ">",$currfilename or die $!;
                                       print FILE $df_free;
                                       close FILE;
                                       }
                               else    {
                                       # space level has't dropped since last check
                                       # if $warning_remind=1 resend low space warning
                                       if ($warning_remind==1) {
                                                $send = 1;
                                                $out = $out . sprintf("\n > $dirs[$i] (%0.2f%%)",$df_free);
                                                }
                                       }
                               } # space-has-dropped end

                     } # interval-reached end
                else {
                     # warning not sent; create statfile and add current disk to warning
                     open FILE, ">",$currfilename or die $!;
                     print FILE $df_free;
                     close FILE or die $!;
                     $send = 1;
                     $out = $out . sprintf("\n > $dirs[$i] (%0.2f%%)",$df_free);
               }
      } # fi

} # rof

$out = $out . "\n";

if ($send==1) {

        # add notice if $warning_remind=0
        if ($warning_remind==0)
              { $out = $out . sprintf("\n\n You will not receive any duplicates of this warning until space level drops again."); };

        # time to send a warning mail

        # send email using UNIX/Linux sendmail
        open(MAIL, "|/usr/sbin/sendmail -t");

        ## Mail Header
        print MAIL "To: $to\n";
        print MAIL "From: $from\n";
        print MAIL "Subject: $subject\n";

        ## Mail Body
        print MAIL $out;

        close(MAIL);
        }

# EOF

2 Comments

Leave a Reply