Skip to content

Instantly share code, notes, and snippets.

@sguter90
Last active November 7, 2017 07:40
Show Gist options
  • Save sguter90/81c4a639dfcfe272a651e985a5ef2e2e to your computer and use it in GitHub Desktop.
Save sguter90/81c4a639dfcfe272a651e985a5ef2e2e to your computer and use it in GitHub Desktop.
check_disk_inodes
#!/usr/bin/perl
=head1 PLUGIN
check_disk_inodes.pl : check inodes of disks on Unix servers
=head1 ENVIRONNEMENT
Linux
=head1 SYNOPSIS
./check_disk_inodes.pl [-H <host>] [-w <num>] [-c <num>] [-u <user>] [-p <path>]
[-i <dev>] [-f <fs>] [-h] [-C <file>]
-h | --help : Display this help
-w | --warning : % free inodes to send warning alert (default 10)
-c | --critical : % free inodes to send critical alert (default 5)
-H | --host : host you want to check by SSH (default localhost)
-u | --user : user for SSH connection (default nagios)
-i | --ignore : Filesystem you want to ignore
format : <name>,<name>,<name>....
-r /pattern/ : include all filesystems matching this regexp
-R /pattern/ : exclude all filesystems matching this regexp
-f | --filesystem : filesystems or device you have to check (default all)
format : <name>:warn:crit,<name>:warn:crit,...
unit for warning and critical values is %
-C | --conf : specify a configuration file for filesystems threshold
definitions
-v | --verbose : plugin output contain all FS(default : output shows
only warning or critical FS).
--srvperf dir : Save datas external files placed on this directory
--html : Add <br> in plugin output to improve the Web interface
output.
-w and -c options allow you to ajust default threshold of all checked fs.
Theses values can be overwritten with -C option by specifying a configuration
file. perldoc ckech_disk_inodes.pl for more details.
If you want to use the SSH connexion and check remote hosts, you must create
a connection without password between your nagios server and the checked host
(key exchange).
=head1 EXAMPLE
=head2 No config file for FS :
All FS will have the same threshold :
not verbose mode :
./check_disk_inodes.pl -w 20 -c 10
DISKS OK
verbose mode :
./check_disk_inodes.pl -w 20 -c 10 -v
DISK OK [/dev/shm 145876 (99% free inodes)] [/usr 178974 (56% free inodes)] [/ 220345 (84%
free inodes)] [/var 110147 (73% free inodes)] [/tmp 14578 (96% free inodes)] [/home 501 (20% free inodes)]
ignore some FS :
./check_disk_inodes.pl -i /dev/shm,/tmp,/home -v
DISK OK [/usr 178974 (56% free inodes)] [/ 220345 (84% free inodes)] [/var 110147 (73% free inodes)]
Specify different threshold :
./check_disk_inodes.pl -w 20 -c 10 -f /usr:30:25 -i /dev/shm,/tmp,/home -v
=head2 With a FS config file :
Syntax (check_disk_inodes.cfg):
#FS WARN CRIT
/ 4000 3000
/home 200 150
/var 10000 5000
FS threshold are read in this configuration file. the -f option will
not be used.
./check_disk_inodes.pl -C check_disk_inodes.cfg -i /dev/shm,/tmp,/home
DISK WARNING [/ 220345 (84% free inodes)]
=cut
use Getopt::Long qw(:config no_ignore_case bundling);
use Pod::Usage;
use strict;
my ($opt_c, $opt_w, $opt_h, $opt_i,$opt_f,$opt_s,$opt_u,$opt_H,$opt_C,$opt_v,
$opt_html, $opt_srvperf, $opt_r, $opt_R);
$opt_u = "nagios";
$opt_i = "";
$opt_w = "10";
$opt_c = "5";
$opt_H = "localhost";
$opt_R = q/^$/;
$opt_r = "";
my $exclude_re = "(^//|^none)";
my %alldisks;
my %checkdisks;
my $diskFreeInodeCmd = "/bin/df -i";
my $output ;
my $retour = 'OK';
my %EXIT_CODES = (
'UNKNOWN' => -1,
'OK' => 0,
'WARNING' => 1,
'CRITICAL' => 2
);
GetOptions(
"h" => \$opt_h, "help" => \$opt_h,
"H=s" => \$opt_H, "host=s" => \$opt_H,
"w=s" => \$opt_w, "warning=s" => \$opt_w,
"c=s" => \$opt_c, "critical=s" => \$opt_c,
"u=s" => \$opt_u, "user=s" => \$opt_u,
"i=s" => \$opt_i, "ignore=s" => \$opt_i,
"f=s" => \$opt_f, "filesystem=s" => \$opt_f,
"C=s" => \$opt_C, "conf=s" => \$opt_C,
"v" => \$opt_v, "verbose" => \$opt_v,
"r=s" => \$opt_r, "R=s" => \$opt_R,
"html" => \$opt_html,
"srvperf=s" => \$opt_srvperf,
) || pod2usage() ;
if ($opt_h) {
pod2usage(-verbose=>1);
exit $EXIT_CODES{'OK'};
}
if(!$opt_H) {
pod2usage();
exit $EXIT_CODES{'UNKNOWN'};
}
my $args;
if($opt_H ne "localhost" and $opt_H ne "127.0.0.1") {
$diskFreeInodeCmd = "ssh $opt_u\@$opt_H '$diskFreeInodeCmd'";
}
my @outputFreeInode = `$diskFreeInodeCmd`;
foreach my $l (@outputFreeInode) {
if($l =~ /(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\%\s+([\/\w\d\.-]+)$/) {
next if ($l =~ m/$opt_R/);
next if ($l !~ m/$opt_r/);
next if ($l =~ m/$exclude_re/);
my ($sumInodes,$usedInodes,$freeInodes,$percentUsedInodes,$disk) = ($1,$2,$3,$4,$5);
$alldisks{$disk}->{inode_pused} = $percentUsedInodes;
$alldisks{$disk}->{inode_pfree} = 100-$percentUsedInodes;
$alldisks{$disk}->{inode_somme} = $sumInodes;
$alldisks{$disk}->{inode_used} = $usedInodes;
$alldisks{$disk}->{inode_free} = $freeInodes;
updateRates($disk,$opt_w,$opt_c,$alldisks{$disk}->{somme});
}
}
use Data::Dumper;
if($opt_f) {
my @fs = split(',',$opt_f);
foreach my $f (@fs) {
# <nom_fs> ou <nom_fs,warn,crit>
if($f =~ /^[\/\w\d]+$/) {
if(defined($alldisks{$f})) {
$checkdisks{$f}=$alldisks{$f};
}
} elsif ($f =~ /([\/\w\d]+)\:(\w+)\:(\w+)/) {
if(defined($alldisks{$1})) {
$checkdisks{$1}=$alldisks{$1};
updateRates($1,$2,$3,$checkdisks{$1}->{somme});
}
} else {
print "option -f invalide\n";
pod2usage();
exit $EXIT_CODES{'UNKNOWN'};
}
}
}
elsif ($opt_C) {
open(FIC,"<$opt_C") or die "$!";
foreach my $l (<FIC>) {
if($l =~ /^([\/\w\d]+)\s+(\w+)\s+(\w+)$/) {
my ($d,$w,$c)=($1,$2,$3);
if(defined($alldisks{$d})) {
$checkdisks{$d}=$alldisks{$d};
updateRates($d,$w,$c,$checkdisks{$d}->{somme});
}
}
}
close(FIC);
}
%checkdisks= (%alldisks, %checkdisks);
if($opt_i) {
my @fs = split(',',$opt_i);
foreach my $f (@fs, "/cdrom", "/mnt/cdrom") {
if(defined($checkdisks{$f})) {
delete $checkdisks{$f};
}
}
}
my $cmp_warn=0;
my $cmp_crit=0;
my $perf_data="";
foreach my $f (keys %checkdisks) {
if($checkdisks{$f}->{inode_pfree} < $checkdisks{$f}->{critical}) {
$cmp_crit++;
$output .= "[$f " . $checkdisks{$f}->{inode_free} .
" (" . $checkdisks{$f}->{inode_pfree} . '% free inodes)] ';
$output .= "<br>" if ($opt_html);
}
elsif ($checkdisks{$f}->{inode_pfree} < $checkdisks{$f}->{warning}) {
$cmp_warn++;
$output .= "[$f " . $checkdisks{$f}->{inode_free} .
" (" . $checkdisks{$f}->{inode_pfree} . '% free inodes)] ';
$output .= "<br>" if ($opt_html);
} else {
if ($opt_v) {
$output .= "[$f " . $checkdisks{$f}->{inode_free} .
" (" . $checkdisks{$f}->{inode_pfree} . '% free inodes)] ';
$output .= "<br>" if ($opt_html);
}
}
# inodes
my $perfwarn=$alldisks{$f}->{inode_somme}*((100-$checkdisks{$f}->{warning})/100);
$perfwarn = sprintf("%0.f",$perfwarn);
my $perfcrit=$alldisks{$f}->{inode_somme}*((100-$checkdisks{$f}->{critical})/100);
$perfcrit = sprintf("%0.f",$perfcrit);
$perf_data.="'$f'=$checkdisks{$f}->{inode_used};".
"$perfwarn;".
"$perfcrit;".
"0;".
"$checkdisks{$f}->{inode_somme} ";
}
if($cmp_crit > 0) {
$retour='CRITICAL';
} elsif ($cmp_warn > 0) {
$retour='WARNING';
} else {
$retour='OK';
}
#time|machine|service|output|perf
if (-d $opt_srvperf) {
eval {
require Mayday;
require Mayday::Config;
my $cfg = new Mayday::Config(version => $Mayday::nagios_version,
cgi_file => $Mayday::nagios_cgi_cfg) ;
die "Can't read nagios configuration" unless $cfg ;
my $host = $cfg->get_host_by_address($opt_H) || $opt_H;
open(FP, ">>$opt_srvperf/$host.perfdata") ;
print FP time(),"|$host|disk|DISK $retour $output|$perf_data\n" ;
close(FP) ;
}
}
print "DISK $retour $output|$perf_data\n";
exit $EXIT_CODES{$retour};
##########################################################################
sub updateRates {
my ($disk,$w,$c,$max) = @_;
if($w =~ m/^(\d+)(\D)/) {
$alldisks{$disk}->{'warning'} = $alldisks{$disk}->{inode_somme}*((100-$w)/100);
} else {
$alldisks{$disk}->{'warning'} = $w;
}
if($c =~ /^(\d+)(\D)/) {
$alldisks{$disk}->{'critical'} = $alldisks{$disk}->{inode_somme}*((100-$c)/100);
} else {
$alldisks{$disk}->{'critical'} = $c;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment