#!/usr/bin/perl -w # check_disk_space.pl # Send an email notice out when mounted file systems are past a given percentage. # # Perl v5.8.8 # Tested under RHEL4, RHEL5, and RHEL6 # # When this script is run it will check the status of all mounted file systems # using the df command and if the percentage is past the given critical set level # will send out an email notice every time it is run. A set warning percentage # only send out an email every number_of_days_before_next_warning. # It keeps track of the number_of_days_before_next_warning using lock files. # # The check_disk_space.xml config file should be in the same directory as the program, # and be given the same name if the program name is changed. # #check_disk_space.xml # < = <, > = > #- # # 90 # 99 # 7 # /home// # yes # no # /bin/df # /bin/find # /bin/rm # /bin/date # /bin/hostname # /usr/sbin/sendmail # user@mail.com # Disk Check <user@system.com> # Disk Check # # Disk Check # #- # # The following config toggles whether the host appears in the subject line. # A value of "yes" will trigger the hostname include. # no # # The following line troggles weather or not lock files are created with a # hidden dot prefix. A value of "yes" will trigger the hidden file. # yes # # The following line determins where the lock files will be placed. If left # blank the lock files will be saved in the current directory. Be sure to # end a directory path with a "/" in the config file. #/home// # # This program doesn't require any special privlege accesses, except read/write # access to the lockfile directory. # # Recommended Crontab Entry: # # Check precentage of disk used every day and send out a email if critical levels are reached. # 0 7 * * * cd /home//bin; /home//bin/check_disk_space.pl # # Script requirements: install XML Simple # yum install perl-XML-Simple # # History: # --------------------------------------------------------------------------- # 2014-02-24 kienenbe Started, works. # use XML::Simple; use File::Basename; #use Data::Dumper; #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> # Get the mount points from the df command. #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> sub get_filesystem_data { my @mount_points; my $df_line; my $filesystem; my $junk; my $total_size; my $amount_used; my $amount_avalible; my $percent_used; my @df_output = `$command_df -lh`; foreach $df_line (@df_output) { if ($df_line =~ m#\d\%#) { #print "->$df_line"; # Break out the needed data. ($percent_used,$filesystem) = split(/% /, $df_line); chomp $filesystem; ($junk,$total_size,$amount_used,$amount_avalible,$percent_used) = split(/\s+/, $percent_used); # Record the data for the filesystem mount point. $filesystem_info{"$filesystem"}{"total_size"} = "$total_size"; $filesystem_info{"$filesystem"}{"amount_used"} = "$amount_used"; $filesystem_info{"$filesystem"}{"amount_avalible"} = "$amount_avalible"; $filesystem_info{"$filesystem"}{"percent_used"} = "$percent_used"; } } } #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> # Format the text report output for display. #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> # system.mysystem.org # Fri Feb 21 13:47:03 UTC 2014 # # ---- Critical file system space at or above 45% ---- # # Size Used Avail Use% Mounted on # 1.8T 769G 973G 45% /mnt/backup # 1.1T 436G 550G 45% /data # # ---- Warning file system space at or above 8% ---- # # Size Used Avail Use% Mounted on # 485M 38M 422M 9% /boot sub format_report_output { $warning_duplicate_check = 0; $critical_duplicate_check = 0; my $filename; # Cycle though each filesystem mount point. foreach my $filesystem (keys %filesystem_info) { if ($filesystem_info{"$filesystem"}{"percent_used"} >= $critical_percent_used) { if ($critical_duplicate_check eq 0) { # Only print the date and time stamp if this is the first warning check. if ($warning_duplicate_check eq 0) { $formated_report .= "\n $Hostname\n $TimeStamp\n"; } $formated_report .= "\n ---- Critical file system space at or above ${critical_percent_used}% ----\n\n"; $formated_report .= sprintf(" %5s %5s %5s %5s %-60s\n", "Size","Used","Avail","Use%","Mounted on"); $critical_duplicate_check = 1; } $formated_report .= sprintf(" %5s %5s %5s %5s %-60s\n", $filesystem_info{$filesystem}{total_size},$filesystem_info{$filesystem}{amount_used},$filesystem_info{$filesystem}{amount_avalible},"$filesystem_info{$filesystem}{percent_used}%",$filesystem); } elsif ($filesystem_info{"$filesystem"}{"percent_used"} >= $warning_percent_used) { # Concert the file system mount point to a file name. $filename = &convert_filesystem_path_to_name($filesystem); # Remove warning locks for file system mount points past the number_of_days_before_next_warning &remove_warning_lockfile($filename); if (&check_for_warning_lockfile($filename)) { # Do nothing } else { if ($warning_duplicate_check eq 0) { # Only print the date and time stamp if this is the first critical check. if ($critical_duplicate_check eq 0) { $formated_report .= "\n $Hostname\n $TimeStamp\n"; } $formated_report .= "\n ---- Warning file system space at or above ${warning_percent_used}% ----\n\n"; $formated_report .= sprintf(" %5s %5s %5s %5s %-60s\n", "Size","Used","Avail","Use%","Mounted on"); $warning_duplicate_check = 1; } $formated_report .= sprintf(" %5s %5s %5s %5s %-60s\n", $filesystem_info{$filesystem}{total_size},$filesystem_info{$filesystem}{amount_used},$filesystem_info{$filesystem}{amount_avalible},"$filesystem_info{$filesystem}{percent_used}%",$filesystem); # Create a warning lock file for the current file system mount point. &write_warning_lockfile($filename); } } } } #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> # Send out the email to the recipients. #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> sub send_email_notice { # Send full report to recepiants(s) # Remove complaint about global empty vars such as ${mail_subject_postfix} no warnings 'uninitialized'; if ( $warning_duplicate_check eq 1 or $critical_duplicate_check eq 1) { open (MAIL, "|$command_sendmail -t") || die "Can't open the mail binary: ${command_sendmail}!\n"; print MAIL "X-Mailer: ${mail_x_mailer}\n"; print MAIL "Return-Path: root\@${Hostname}\n"; print MAIL "From: ${mail_from} \n"; print MAIL "To: ${mail_to}\n"; if ($Include_Hostname_In_Subject eq "yes") { print MAIL "Subject: ${mail_subject_prefix}${Hostname}${mail_subject_postfix}\n\n"; } else { print MAIL "Subject: ${mail_subject_prefix}${mail_subject_postfix}\n\n"; } print MAIL "\n${formated_report}\n\n"; close (MAIL); } } #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> # Conver the file system mount point to a lockfile name. #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> sub convert_filesystem_path_to_name { my $filesystem_path = shift; my $lockfile_name; $filesystem_path =~ s#/#_#g; $filesystem_path =~ s# #_#g; if ($hide_warning_lockfile eq "yes") { $lockfile_name = "." . $program_name . "_warning_lock" . $filesystem_path; } else { $lockfile_name = $program_name . "_warning_lock" . $filesystem_path; } return ($lockfile_name); } #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> # Save the warning lockfile #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> # Creates the locking file in the format of: # / are converted to underscores for mount point. # <.><_warning_lock> # # -rwxr-x---. 1 user user 9211 Feb 21 13:46 df.pl* # -rw-rw-r--. 1 user user 0 Feb 21 13:47 .df_warning_lock_boot sub write_warning_lockfile { my $lockfile_name = shift; my $lockfile_directory = "./"; # Check if the $warning_lock_directory has been set. # If so use it instead of the current directory. if ( $warning_lock_directory) { $lockfile_directory = $warning_lock_directory; } # Check for the warning lockfile. # If it already exists exit. if ( -e "${lockfile_directory}${lockfile_name}" ) { return; } open (WARNING_LOCKFILE, '>', ${lockfile_directory}.${lockfile_name}) or $formated_report .= "\nUnable to save warning lockfile for ${lockfile_directory}${lockfile_name}\n Warnings will be sent out every time the script runs.\n\n"; close (WARNING_LOCKFILE); } #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> # Check for the warning lockfile #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> sub check_for_warning_lockfile { my $lockfile_name = shift; my $lockfile_directory = "./"; # Check if the $warning_lock_directory has been set. # If so use it instead of the current directory. if ( $warning_lock_directory) { $lockfile_directory = $warning_lock_directory; } # Check for the warning lockfile. if ( -e "${lockfile_directory}${lockfile_name}" ) { return 1; } else { return 0; } } #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> # Remove the warning lockfile #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> sub remove_warning_lockfile { my $lockfile_name = shift; my $lockfile_directory = "./"; # Check if the $warning_lock_directory has been set. # If so use it instead of the current directory. if ( $warning_lock_directory) { $lockfile_directory = $warning_lock_directory; } # If the file doesn't exist just exit. if (! -e "${lockfile_directory}${lockfile_name}" ) { return; } # Remove the warning lockfile. `$command_find ${lockfile_directory}${lockfile_name} -mtime +${number_of_days_before_next_warning} -type f -exec $command_rm -f {} \\;`; } # Run the main routine. &Start; #>>>>>>>>>>>>> #> Main Start #>>>>>>>>>>>>> sub Start { #declare all major variables used in this subroutine. local (%filesystem_info, $TimeStamp, $Hostname, $formated_report, $warning_duplicate_check, $critical_duplicate_check, $program_name); # Obtain configuration from a file with a name inferred from this # script's name. ($program_name) = split(/\./, basename($0)); my $program_full_name =basename($0); # if you don not wish to use XML::Simple comment out next line.. $config = XMLin("${program_name}.xml", SuppressEmpty => 'undef'); # if you don not wish to use XML::Simple configure variable directly here. # if you don't use the XML config file you must place a "\" in front of the # "@" in your email address so it is not interpreted as an array variable. # ex: local $mail_to = "vadapt.notice\@gmail.com"; local $command_date = $config->{'command_date'}; local $command_df = $config->{'command_df'}; local $command_find = $config->{'command_find'}; local $command_hostname = $config->{'command_hostname'}; local $command_rm = $config->{'command_rm'}; local $command_sendmail = $config->{'command_sendmail'}; local $warning_percent_used = $config->{'warning_percent_used'}; local $critical_percent_used = $config->{'critical_percent_used'}; local $number_of_days_before_next_warning = $config->{'number_of_days_before_next_warning'}; local $warning_lock_directory = $config->{'warning_lock_directory'}; local $hide_warning_lockfile = $config->{'hide_warning_lockfile'}; local $Include_Hostname_In_Subject = $config->{'Include_Hostname_In_Subject'}; local $mail_to = $config->{'mail_to'}; local $mail_from = $config->{'mail_from'}; local $mail_subject_prefix = $config->{'mail_subject_prefix'}; local $mail_subject_postfix = $config->{'mail_subject_postfix'}; local $mail_x_mailer = $config->{'mail_x_mailer'}; # Get the hostname local $Hostname = `$command_hostname -f`; chomp $Hostname; # Get the date timestamp $TimeStamp = `$command_date`; chomp $TimeStamp; # Do the work &get_filesystem_data; &format_report_output; &send_email_notice; # uncomment to print report when run. #print $formated_report; #End the program exit; }