432 lines
12 KiB
Plaintext
432 lines
12 KiB
Plaintext
|
#!/usr/bin/perl
|
||
|
use strict;
|
||
|
my $VERSION = '0.2';
|
||
|
my $COPYRIGHT = 'Copyright (C) 2005-2011 Jonathan Buhacoff <jonathan@buhacoff.net>';
|
||
|
my $LICENSE = 'http://www.gnu.org/licenses/gpl.txt';
|
||
|
my %status = ( 'OK' => 0, 'WARNING' => 1, 'CRITICAL' => 2, 'UNKNOWN' => 3 );
|
||
|
|
||
|
#### IDEA AND INITIAL IMPLEMENTATION BASED ON CHECK_IMAP_RECEIVE WAS CONTRIBUTED BY JOHAN ROMME from THE NETHERLANDS 14 Oct 2011
|
||
|
|
||
|
# look for required modules
|
||
|
exit $status{UNKNOWN} unless load_modules(qw/Getopt::Long Mail::IMAPClient/);
|
||
|
|
||
|
BEGIN {
|
||
|
if( grep { /^--hires$/ } @ARGV ) {
|
||
|
eval "use Time::HiRes qw(time);";
|
||
|
warn "Time::HiRes not installed\n" if $@;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# get options from command line
|
||
|
Getopt::Long::Configure("bundling");
|
||
|
my $verbose = 0;
|
||
|
my $help = "";
|
||
|
my $help_usage = "";
|
||
|
my $show_version = "";
|
||
|
my $imap_server = "";
|
||
|
my $default_imap_port = "143";
|
||
|
my $default_imap_ssl_port = "993";
|
||
|
my $imap_port = "";
|
||
|
my $username = "";
|
||
|
my $password = "";
|
||
|
my $mailbox = "INBOX";
|
||
|
my $warntime = 15;
|
||
|
my $criticaltime = 30;
|
||
|
my $timeout = 60;
|
||
|
my $peek = "";
|
||
|
my $ssl = 0;
|
||
|
my $tls = 0;
|
||
|
my $time_hires = "";
|
||
|
my $ok;
|
||
|
$ok = Getopt::Long::GetOptions(
|
||
|
"V|version"=>\$show_version,
|
||
|
"v|verbose+"=>\$verbose,"h|help"=>\$help,"usage"=>\$help_usage,
|
||
|
"w|warning=i"=>\$warntime,"c|critical=i"=>\$criticaltime,"t|timeout=i"=>\$timeout,
|
||
|
# imap settings
|
||
|
"H|hostname=s"=>\$imap_server,"p|port=i"=>\$imap_port,
|
||
|
"U|username=s"=>\$username,"P|password=s"=>\$password, "m|mailbox=s"=>\$mailbox,
|
||
|
"ssl!"=>\$ssl, "tls!"=>\$tls,
|
||
|
# search settings
|
||
|
"peek!"=>\$peek,
|
||
|
# Time
|
||
|
"hires"=>\$time_hires,
|
||
|
);
|
||
|
|
||
|
if( $show_version ) {
|
||
|
print "$VERSION\n";
|
||
|
if( $verbose ) {
|
||
|
print "Default warning threshold: $warntime seconds\n";
|
||
|
print "Default critical threshold: $criticaltime seconds\n";
|
||
|
print "Default timeout: $timeout seconds\n";
|
||
|
}
|
||
|
exit $status{UNKNOWN};
|
||
|
}
|
||
|
|
||
|
if( $help ) {
|
||
|
exec "perldoc", $0 or print "Try `perldoc $0`\n";
|
||
|
exit $status{UNKNOWN};
|
||
|
}
|
||
|
|
||
|
my @required_module = ();
|
||
|
push @required_module, 'IO::Socket::SSL' if $ssl || $tls;
|
||
|
exit $status{UNKNOWN} unless load_modules(@required_module);
|
||
|
|
||
|
if( $help_usage
|
||
|
||
|
||
|
( $imap_server eq "" || $username eq "" || $password eq "" )
|
||
|
) {
|
||
|
print "Usage: $0 -H host [-p port] -U username -P password [--imap-retries <tries>]\n";
|
||
|
exit $status{UNKNOWN};
|
||
|
}
|
||
|
|
||
|
|
||
|
# initialize
|
||
|
my $report = new PluginReport;
|
||
|
my $time_start = time;
|
||
|
|
||
|
# connect to IMAP server
|
||
|
print "connecting to server $imap_server\n" if $verbose > 2;
|
||
|
my $imap;
|
||
|
eval {
|
||
|
local $SIG{ALRM} = sub { die "exceeded timeout $timeout seconds\n" }; # NB: \n required, see `perldoc -f alarm`
|
||
|
alarm $timeout;
|
||
|
|
||
|
if( $ssl || $tls ) {
|
||
|
$imap_port = $default_imap_ssl_port unless $imap_port;
|
||
|
my $socket = IO::Socket::SSL->new("$imap_server:$imap_port");
|
||
|
die IO::Socket::SSL::errstr() unless $socket;
|
||
|
$socket->autoflush(1);
|
||
|
$imap = Mail::IMAPClient->new(Socket=>$socket, Debug => 0 );
|
||
|
$imap->State(Mail::IMAPClient->Connected);
|
||
|
$imap->_read_line() if "$Mail::IMAPClient::VERSION" le "2.2.9"; # necessary to remove the server's "ready" line from the input buffer for old versions of Mail::IMAPClient. Using string comparison for the version check because the numeric didn't work on Darwin and for Mail::IMAPClient the next version is 2.3.0 and then 3.00 so string comparison works
|
||
|
$imap->User($username);
|
||
|
$imap->Password($password);
|
||
|
$imap->login() or die "$@";
|
||
|
}
|
||
|
else {
|
||
|
$imap_port = $default_imap_port unless $imap_port;
|
||
|
$imap = Mail::IMAPClient->new(Debug => 0 );
|
||
|
$imap->Server("$imap_server:$imap_port");
|
||
|
$imap->User($username);
|
||
|
$imap->Password($password);
|
||
|
$imap->connect() or die "$@";
|
||
|
}
|
||
|
|
||
|
$imap->Peek(1) if $peek;
|
||
|
$imap->Ignoresizeerrors(1);
|
||
|
|
||
|
alarm 0;
|
||
|
};
|
||
|
if( $@ ) {
|
||
|
chomp $@;
|
||
|
print "IMAP QUOTA CRITICAL - Could not connect to $imap_server port $imap_port: $@\n";
|
||
|
exit $status{CRITICAL};
|
||
|
}
|
||
|
unless( $imap ) {
|
||
|
print "IMAP QUOTA CRITICAL - Could not connect to $imap_server port $imap_port: $@\n";
|
||
|
exit $status{CRITICAL};
|
||
|
}
|
||
|
my $time_connected = time;
|
||
|
|
||
|
my $quotaUsed;
|
||
|
my $quotaLimit;
|
||
|
my $quotaPercentage;
|
||
|
my $quotaPercentageWarning = 80;
|
||
|
my $quotaPercentageCritical = 90;
|
||
|
my $quotaMessage;
|
||
|
|
||
|
# look for the quota limits
|
||
|
my $tries = 0;
|
||
|
my @msgs;
|
||
|
|
||
|
eval {
|
||
|
my $k;
|
||
|
my @l = $imap->getquotaroot();
|
||
|
foreach $k (@l) {
|
||
|
print "$k\n" if $verbose > 2;
|
||
|
if ($k =~ /STORAGE +(\d+) +(\d+)/) {
|
||
|
$quotaUsed = $1;
|
||
|
$quotaLimit = $2;
|
||
|
}
|
||
|
}
|
||
|
if (!length($quotaUsed) && !length($quotaLimit)) {
|
||
|
print "no answer from imap host\n" if $verbose > 2;
|
||
|
} elsif (!length($quotaUsed) || !length($quotaLimit) {
|
||
|
print "incorrect answer from imap host\n";
|
||
|
$imap->close();
|
||
|
exit $status{UNKNOWN};
|
||
|
} else {
|
||
|
$quotaPercentage = sprintf("%.1f", (100 * $quotaUsed) / $quotaLimit);
|
||
|
$quotaMessage = "$quotaUsed $quotaLimit - $quotaPercentage%";
|
||
|
}
|
||
|
};
|
||
|
if( $@ ) {
|
||
|
chomp $@;
|
||
|
print "IMAP QUOTA CRITICAL - Could not check quota at $imap_server port $imap_port: $@\n";
|
||
|
exit $status{CRITICAL};
|
||
|
}
|
||
|
|
||
|
|
||
|
# disconnect from IMAP server
|
||
|
print "disconnecting from server\n" if $verbose > 2;
|
||
|
$imap->logout();
|
||
|
|
||
|
# calculate elapsed time and issue warnings
|
||
|
my $time_end = time;
|
||
|
my $elapsedtime = $time_end - $time_start;
|
||
|
$report->{seconds} = $elapsedtime;
|
||
|
|
||
|
# print report and exit with known status
|
||
|
|
||
|
if($quotaPercentage >= $quotaPercentageCritical) {
|
||
|
print "IMAP QUOTA CRITICAL - $quotaMessage\n";
|
||
|
exit $status{CRITICAL};
|
||
|
}
|
||
|
if($quotaPercentage >= $quotaPercentageWarning) {
|
||
|
print "IMAP QUOTA WARNING - $quotaMessage\n";
|
||
|
exit $status{WARNING};
|
||
|
}
|
||
|
print "IMAP QUOTA OK - $quotaMessage\n";
|
||
|
exit $status{OK};
|
||
|
|
||
|
|
||
|
# utility to load required modules. exits if unable to load one or more of the modules.
|
||
|
sub load_modules {
|
||
|
my @missing_modules = ();
|
||
|
foreach( @_ ) {
|
||
|
eval "require $_";
|
||
|
push @missing_modules, $_ if $@;
|
||
|
}
|
||
|
if( @missing_modules ) {
|
||
|
print "Missing perl modules: @missing_modules\n";
|
||
|
return 0;
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
# NAME
|
||
|
# PluginReport
|
||
|
# SYNOPSIS
|
||
|
# $report = new PluginReport;
|
||
|
# $report->{label1} = "value1";
|
||
|
# $report->{label2} = "value2";
|
||
|
# print $report->text(qw/label1 label2/);
|
||
|
package PluginReport;
|
||
|
|
||
|
sub new {
|
||
|
my ($proto,%p) = @_;
|
||
|
my $class = ref($proto) || $proto;
|
||
|
my $self = bless {}, $class;
|
||
|
$self->{$_} = $p{$_} foreach keys %p;
|
||
|
return $self;
|
||
|
}
|
||
|
|
||
|
sub text {
|
||
|
my ($self,@labels) = @_;
|
||
|
my @report = map { "$self->{$_} $_" } grep { defined $self->{$_} } @labels;
|
||
|
my $text = join(", ", @report);
|
||
|
return $text;
|
||
|
}
|
||
|
|
||
|
|
||
|
package main;
|
||
|
1;
|
||
|
|
||
|
__END__
|
||
|
|
||
|
|
||
|
=pod
|
||
|
|
||
|
=head1 NAME
|
||
|
|
||
|
check_imap_quota - connects to an IMAP account and checks the quota
|
||
|
|
||
|
=head1 SYNOPSIS
|
||
|
|
||
|
check_imap_quota -vV
|
||
|
check_imap_quota -?
|
||
|
check_imap_quota --help
|
||
|
|
||
|
=head1 OPTIONS
|
||
|
|
||
|
=over
|
||
|
|
||
|
=item --warning <seconds>
|
||
|
|
||
|
Warn if it takes longer than <seconds> to connect to the IMAP server. Default is 15 seconds.
|
||
|
Also known as: -w <seconds>
|
||
|
|
||
|
=item --critical <seconds>
|
||
|
|
||
|
Return a critical status if it takes longer than <seconds> to connect to the IMAP server. Default is 30 seconds.
|
||
|
See also: --capture-critical <messages>
|
||
|
Also known as: -c <seconds>
|
||
|
|
||
|
=item --timeout <seconds>
|
||
|
|
||
|
Abort with critical status if it takes longer than <seconds> to connect to the IMAP server. Default is 60 seconds.
|
||
|
The difference between timeout and critical is that, with the default settings, if it takes 45 seconds to
|
||
|
connect to the server then the connection will succeed but the plugin will return CRITICAL because it took longer
|
||
|
than 30 seconds.
|
||
|
Also known as: -t <seconds>
|
||
|
|
||
|
=item --hostname <server>
|
||
|
|
||
|
Address or name of the IMAP server. Examples: mail.server.com, localhost, 192.168.1.100
|
||
|
Also known as: -H <server>
|
||
|
|
||
|
=item --port <number>
|
||
|
|
||
|
Service port on the IMAP server. Default is 143. If you use SSL, default is 993.
|
||
|
Also known as: -p <number>
|
||
|
|
||
|
=item --username <username>
|
||
|
|
||
|
=item --password <password>
|
||
|
|
||
|
Username and password to use when connecting to IMAP server.
|
||
|
Also known as: -U <username> -P <password>
|
||
|
|
||
|
=item --mailbox <mailbox>
|
||
|
|
||
|
Use this option to specify the mailbox to search for messages. Default is INBOX.
|
||
|
Also known as: -m <mailbox>
|
||
|
|
||
|
=item --ssl
|
||
|
|
||
|
=item --nossl
|
||
|
|
||
|
Enable SSL protocol. Requires IO::Socket::SSL.
|
||
|
|
||
|
Using this option automatically changes the default port from 143 to 993. You can still
|
||
|
override this from the command line using the --port option.
|
||
|
|
||
|
Use the nossl option to turn off the ssl option.
|
||
|
|
||
|
=item --hires
|
||
|
|
||
|
Use the Time::HiRes module to measure time, if available.
|
||
|
|
||
|
=item --verbose
|
||
|
|
||
|
Display additional information. Useful for troubleshooting. Use together with --version to see the default
|
||
|
warning and critical timeout values.
|
||
|
|
||
|
If the selected mailbox was not found, you can use verbosity level 3 (-vvv) to display a list of all
|
||
|
available mailboxes on the server.
|
||
|
|
||
|
Also known as: -v
|
||
|
|
||
|
=item --version
|
||
|
|
||
|
Display plugin version and exit.
|
||
|
Also known as: -V
|
||
|
|
||
|
=item --help
|
||
|
|
||
|
Display this documentation and exit. Does not work in the ePN version.
|
||
|
Also known as: -h
|
||
|
|
||
|
=item --usage
|
||
|
|
||
|
Display a short usage instruction and exit.
|
||
|
|
||
|
=back
|
||
|
|
||
|
=head1 EXAMPLES
|
||
|
|
||
|
=head2 Report how many emails are in the mailbox
|
||
|
|
||
|
$ check_imap_receive -H mail.server.net --username mailuser --password mailpass
|
||
|
-s ALL --nodelete
|
||
|
|
||
|
IMAP RECEIVE OK - 1 seconds, 7 found
|
||
|
|
||
|
=head2 Report the email with the highest value
|
||
|
|
||
|
Suppose your mailbox has some emails from an automated script and that a message
|
||
|
from this script typically looks like this (abbreviated):
|
||
|
|
||
|
To: mailuser@server.net
|
||
|
From: autoscript@server.net
|
||
|
Subject: Results of Autoscript
|
||
|
Date: Wed, 09 Nov 2005 08:30:40 -0800
|
||
|
Message-ID: <auto-000000992528@server.net>
|
||
|
|
||
|
Homeruns 5
|
||
|
|
||
|
And further suppose that you are interested in reporting the message that has the
|
||
|
highest number of home runs, and also to leave this message in the mailbox for future
|
||
|
checks, but remove the other matching messages with lesser values:
|
||
|
|
||
|
$ check_imap_receive -H mail.server.net --username mailuser --password mailpass
|
||
|
-s SUBJECT -s "Results of Autoscript" --capture-max "Homeruns (\d+)" --nodelete-captured
|
||
|
|
||
|
IMAP RECEIVE OK - 1 seconds, 3 found, 1 captured, 5 max, 2 deleted
|
||
|
|
||
|
=head2 Troubleshoot your search parameters
|
||
|
|
||
|
Add the --nodelete and --imap-retries=1 parameters to your command line.
|
||
|
|
||
|
=head1 EXIT CODES
|
||
|
|
||
|
Complies with the Nagios plug-in specification:
|
||
|
0 OK The plugin was able to check the service and it appeared to be functioning properly
|
||
|
1 Warning The plugin was able to check the service, but it appeared to be above some "warning" threshold or did not appear to be working properly
|
||
|
2 Critical The plugin detected that either the service was not running or it was above some "critical" threshold
|
||
|
3 Unknown Invalid command line arguments were supplied to the plugin or the plugin was unable to check the status of the given hosts/service
|
||
|
|
||
|
=head1 NAGIOS PLUGIN NOTES
|
||
|
|
||
|
Nagios plugin reference: http://nagiosplug.sourceforge.net/developer-guidelines.html
|
||
|
|
||
|
This plugin does NOT use Nagios DEFAULT_SOCKET_TIMEOUT (provided by utils.pm as $TIMEOUT) because
|
||
|
the path to utils.pm must be specified completely in this program and forces users to edit the source
|
||
|
code if their install location is different (if they realize this is the problem). You can view
|
||
|
the default timeout for this module by using the --verbose and --version options together. The
|
||
|
short form is -vV.
|
||
|
|
||
|
Other than that, it attempts to follow published guidelines for Nagios plugins.
|
||
|
|
||
|
=head1 SEE ALSO
|
||
|
|
||
|
http://nagios.org/
|
||
|
http://search.cpan.org/~djkernen/Mail-IMAPClient-2.2.9/IMAPClient.pod
|
||
|
http://search.cpan.org/~markov/Mail-IMAPClient-3.00/lib/Mail/IMAPClient.pod
|
||
|
|
||
|
=head1 CHANGES
|
||
|
|
||
|
Fri Nov 11 04:53:09 AST 2011
|
||
|
+ version 0.1 created with quota code contributed by Johan Romme
|
||
|
|
||
|
Tue Dec 20 17:38:04 PST 2011
|
||
|
+ fixed bug where a quota of 0 was reported as an incorrect response from the server, thanks to Eike Arndt
|
||
|
+ version 0.2
|
||
|
|
||
|
=head1 AUTHOR
|
||
|
|
||
|
Jonathan Buhacoff <jonathan@buhacoff.net>
|
||
|
|
||
|
=head1 COPYRIGHT AND LICENSE
|
||
|
|
||
|
Copyright (C) 2011 Jonathan Buhacoff
|
||
|
|
||
|
This program is free software; you can redistribute it and/or modify
|
||
|
it under the terms of the GNU General Public License as published by
|
||
|
the Free Software Foundation; either version 3 of the License, or
|
||
|
(at your option) any later version.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
|
||
|
http://www.gnu.org/licenses/gpl.txt
|
||
|
|
||
|
=cut
|
||
|
|