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
Nice script! Please correct string 72: my @lines = ;
Thanks for pointing out the typo.