diff --git a/runtime/README.md b/runtime/README.md new file mode 100644 index 0000000..d64ed9a --- /dev/null +++ b/runtime/README.md @@ -0,0 +1,190 @@ +Kolab Groupware Plugins for Monitoring +====================================== + +The plugins in this repository have been specifically authored for Kolab +Groupware, that may or may not be managed by a configuration management suite +such as Puppet. + +Many of the Nagios plugins you might find on the web, for example, do not: + +* **accept `--extra-opts` parameters**, + + which in combination with a generated `plugins.ini` would allow you to + distribute configuration across staging environments, + +* **monitor services end-to-end**, + + which in elastic, distributed environments (scaled horizontally) is a + prerequisite in monitoring and reporting, + +* **simply don't exist**, + + Such as `check_saslauthd`, for which you will want a functional test rather + than a standard `check_nrpe_proc` check. + +Munin plugins you might find may not be representatively trending performance -- +some count files in `/var/lib/imap/proc/` -- such as the plugin ours is based on +-- which may contain stale files, misrepresenting the number of connections, +authenticated connections and number of unique users. This used to be the case +for the `cyrus-imapd` Load graphing: + +![Cyrus IMAP Discrete Murder Topology Frontend Load Graph](https://raw.github.com/kanarip/monitoring-plugins-kolab/master/munin/images/cyrus-imapd_murder_load-day.png) + +Our solution to miscounting is rather simple, and our plugin uses +`lsof +d /var/lib/imap/proc/` to list proc files actually in use. + +`check_email_delivery` +---------------------- + +Example for the *check_email_delivery* plugin: + + ./check_email_delivery \ + --plugin=./check_smtp_send \ + --plugin=./check_imap_receive \ + --hostname=localhost \ + --imap-username=john.doe@example.org \ + --imap-password=somepass \ + --mail-from=john.doe@example.org \ + --mail-to=john.doe@example.org \ + --mail-subject='Something Unique' + +The plugin will submit a message with the corresponding ``To:``, ``From:`` and +``Subject:`` headers (using the ``localhost`` SMTP server, which in this example +has ``127.0.0.0/8`` in `postconf mynetworks` and +``permit_mynetworks`` in its ``smtpd_recipient_restrictions``), and check the +IMAP server (also at ``localhost``) for delivery, and if the message is found, +flag it as `\Seen`, `\Deleted` and EXPUNGE the folder. + +A more complex example may be: + + ./check_email_delivery \ + --plugin=./check_smtp_send \ + --plugin=./check_imap_receive \ + --smtp-server=smtp.example.org \ + --smtp-username=jane.doe@example.org \ + --smtp-password=janespass \ + --smtp-port=587 \ + --smtp-starttls \ + --imap-server=imap.example.org \ + --imap-username=john.doe@example.org \ + --imap-password=johnspass \ + --imap-starttls \ + --imap-mailbox='Filtered Monitoring Messages' \ + --mail-from=john.doe@example.org \ + --mail-to=jane.doe@example.org \ + --mail-subject='Something Unique' \ + --mail-header='X-Nagios-Check: %TOKEN1%' + +What this checks, end-to-end, is the following: + +1. Connection to submission, +2. STARTTLS for Submission, +3. Authentication against submission, +4. The Kolab SMTP Access Policy, +5. Relay on to the IMAP backend servers (over LMTP or SMTP), +6. Mail delivery to mailboxes on the IMAP backend servers (usually over LMTP), +7. Sieve filtering (optionally), +8. IMAP frontend connectivity, +9. STARTLS for IMAP, +10. IMAP proxy capability (what backend mailserver is this mailbox on), +11. Performance. + +For environments that indeed do use staging, or have a shared Nagios set up for +an otherwise multi-tenant environment, it is useful to not have to specify each +of these plugin switches in the Nagios server `commands.cfg` configuration file, +or `nrpe.cfg` target host configuration file. + +We have therefore added the use of `--extra-opts`, and the intended use is to +distribute different `/etc/nagios/plugins.ini` files to systems that require +such. + +For example, a standalone development system might want to connect to the SMTP +and IMAP server using address `localhost`: + + [check_email_delivery] + starttls=true + username=john.doe@example.org + **hostname=localhost** + **password=devpass** + (...) + +while a production system (in a distributed environment) might need to connect +with the SMTP server on address `smtp.example.org`, and the IMAP server on +address `imap.example.org`: + + [check_email_delivery] + starttls=true + username=john.doe@example.org + **smtp-server=smtp.example.org** + **password=prodpass** + **imap-server=imap.example.org** + (...) + +You can now specify a simple command in the Nagios server's `commands.cfg` +configuration file: + + define command { + command_name check_nrpe_smarthost_delivery + command_line $USER1$/check_nrpe -H $HOSTADDRESS$ -c check_smarthost_delivery -a $ARG1$ $TIMET$ + } + + define command { + command_name check_nrpe_submission_delivery + command_line $USER1$/check_nrpe -H $HOSTADDRESS$ -c check_submission_delivery -a $ARG1$ $ARG2$ $TIMET$ + } + +while in the Nagios target host configuration file `nrpe.cfg` you might specify +(line-breaks for legibility): + + command[check_smarthost_delivery]=/usr/lib64/nagios/plugins/check_email_delivery \ + --plugin=/usr/lib64/nagios/plugins/check_smtp_send \ + --plugin=/usr/lib64/nagios/plugins/check_imap_receive \ + --extra-opts=$ARG1$ --mail-subject=smarthost_$ARG2$ + + command[check_submission_delivery]=/usr/lib64/nagios/plugins/check_email_delivery \ + --plugin=/usr/lib64/nagios/plugins/check_smtp_send \ + --plugin=/usr/lib64/nagios/plugins/check_imap_receive \ + --extra-opts=$ARG1$ --smtp-server=$ARG2$ --mail-subject=submission_$ARG3$ + +Services definitions might look as follows, + +* for each webserver and each Cyrus IMAP backend server in a discrete Murder + topology): + + define service { + use mail-delivery-check-service + host_name <%= webserver %> + service_description smarthost/<%= backendserver.split('.')[0] %> + check_command check_nrpe_smarthost_delivery!check_smarthost_<%= backendserver.split('.')[0] %> + } + +* for each webserver, each mail exchanger and each backend server in a + discrete Murder topology): + + define service { + use mail-delivery-check-service + host_name <%= webserver %> + service_description submission/<%= mxserver.split('.')[0] -%>/<%= backendserver.split('.')[0] %> + check_command check_nrpe_submission_delivery!check_submission_<%= backendserver.split('.')[0] -%>!<%= mxserver %> + } + +In a real-life scenario, which could best be described as an elastic, +distributed environment -- with separate web servers, mail exchangers and Cyrus +IMAP backends in a discrete Murder topology, what we are interested in is both +smarhost relay delivery from our webservers (whom send out notification emails +to our users), and (authenticated) submission delivery such as users perform it. + +Checking the availability of each individual service is merely assisting a +system administrator in trying to determine **what** component of the end-to-end +functionality is misbehaving. To detect what functionality is impacted or lost, +the service is monitored end-to-end, and in a full mesh: + +* `$x` web servers, times +* `$y` mail exchangers, times +* `$z` IMAP backend servers, times +* 2 types of service checks (smarthost relay and submission). + +Makes for 16 end-to-end service checks if you have 2 servers of each type, and +54 service checks if you have 3 of each type. Multiply using your own numbers +before assessing whether or not it is reasonable to lower the check frequency in +your environment. diff --git a/runtime/munin/cyrus-imapd b/runtime/munin/cyrus-imapd new file mode 100755 index 0000000..f4885fa --- /dev/null +++ b/runtime/munin/cyrus-imapd @@ -0,0 +1,87 @@ +#!/bin/sh + +# Copyright (C) 2009 Andreas Thienemann +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Library General Public License as published by +# the Free Software Foundation; version 2 only +# +# 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 Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +# +# Plugin to monitor the load on a cyrus imapd server +# +# Usage: Link or copy into the munin-node plugin directory +# +# Installation node: Should most likely run as root: +# [cyrus-imapd] +# user root +# +# +# Magic markers (optional - only used by munin-config and some +# installation scripts): +# +#%# family=contrib +#%# capabilities=autoconf + +# IMAP Configuration Directory +CONFIGDIR=$(awk -F : '/^configdirectory:/ { gsub(/ /, "", $2); print $2 }' /etc/imapd.conf 2> /dev/null) +PROCDIR="${CONFIGDIR}/proc" + +if [ "$1" = "autoconf" ]; then + if [ "x${CONFIGDIR}x" != "xx" ] && [ -d ${PROCDIR} ]; then + echo yes + else + echo no + fi + exit 0 +fi + +# Check if we actually got some sensible data +if [ "x${CONFIGDIR}x" == "xx" ]; then + exit 1 +fi + +# If run with the "config"-parameter, give out information on how the +# graphs should look. + +if [ "$1" = "config" ]; then + echo 'graph_title Cyrus IMAPd Load' + echo 'graph_args --base 1000 -l 0' + echo 'graph_vlabel connections' + echo 'graph_scale no' + echo 'graph_category cyrus' + echo 'graph_info Current connections to the imap server. bawue.net e.V. Trac repository.' + echo 'graph_order connections authenticated_users unique_users' + echo 'connections.label Connections' + echo 'connections.info Number of connections to the imap server.' + echo 'authenticated_users.label Authenticated Users' + echo 'authenticated_users.info Number of authenticated users logged into the imap server.' + echo 'unique_users.label Unique Users' + echo 'unique_users.info Number of unique users on the imap server.' + + # Last, if run with the "config"-parameter, quit here (don't + # display any data) + exit 0 +fi + +procs=$(lsof +d ${PROCDIR} | grep -v NAME | awk '{print $9}') +# Print the number of connections to the imap server +echo "connections.value $(echo "${procs}" | wc -l)" + +# Read the proc files and get the logged in users +echo -n "authenticated_users.value " +awk '{ split(substr($0, match($0, "]")+1), a); if (a[1] != "") print a[1] }' ${procs} 2>/dev/null | wc -l + +# Read the proc files and get the number of unique users +echo -n "unique_users.value " +awk '{ split(substr($0, match($0, "]")+1), a); if (a[1] != "") print a[1] }' ${procs} 2>/dev/null | sort -u | wc -l + diff --git a/runtime/munin/haproxy b/runtime/munin/haproxy new file mode 100755 index 0000000..d43a991 --- /dev/null +++ b/runtime/munin/haproxy @@ -0,0 +1,60 @@ +#!/bin/bash +# +# Copyright (C) 2015 Jeroen van Meeuwen (Kolab Systems) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Library General Public License as published by +# the Free Software Foundation; version 2 only +# +# 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 Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +if [ "$1" == "autoconf" ]; then + echo yes + exit 0 +fi + +function get_stats() { + if [ -f /var/lib/munin/haproxy.state ]; then + return + fi + + echo "show stat" | socat /var/tmp/haproxy.sock stdio > /var/lib/munin/haproxy.state +} + +function list_frontends() { + grep FRONTEND /var/lib/munin/haproxy.state | awk -F',' '{print $1}' +} + +function list_backends() { + grep BACKEND /var/lib/munin/haproxy.state | awk -F',' '{print $1}' +} + +if [ "$1" == "config" ]; then + echo "multigraph haproxy" + echo "graph_category haproxy" + echo "graph_title haproxy statistics" + echo "graph_order active_servers_by_backend" + + echo "graph_order $(for backend in $(list_backends); do + echo -n " ${frontend}=haproxy.${backend}" + done)" + echo "" + for frontend in $(list_frontends); do + echo "haproxy.${frontend}.info Statistics for frontend ${frontend}" + echo "haproxy.${frontend}.label ${frontend}" + echo "haproxy.${frontend}.type COUNTER" + done +fi + +get_stats + +list_backends +list_frontends diff --git a/runtime/munin/images/cyrus-imapd_murder_load-day.png b/runtime/munin/images/cyrus-imapd_murder_load-day.png new file mode 100644 index 0000000..80420c0 Binary files /dev/null and b/runtime/munin/images/cyrus-imapd_murder_load-day.png differ diff --git a/runtime/munin/images/roundcubemail-day.png b/runtime/munin/images/roundcubemail-day.png new file mode 100644 index 0000000..c223ec5 Binary files /dev/null and b/runtime/munin/images/roundcubemail-day.png differ diff --git a/runtime/munin/roundcubemail b/runtime/munin/roundcubemail new file mode 100755 index 0000000..aef5d07 --- /dev/null +++ b/runtime/munin/roundcubemail @@ -0,0 +1,149 @@ +#!/bin/sh + +# Copyright (C) 2012 Jeroen van Meeuwen (Kolab Systems) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Library General Public License as published by +# the Free Software Foundation; version 2 only +# +# 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 Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +# +# Plugin to graph; +# +# - the average duration of mail previews in Roundcube +# +# Usage: Link or copy into the munin-node plugin directory +# +# Installation node: Should most likely run as root: +# [rc-mailpreview] +# user root +# +# +# Magic markers (optional - only used by munin-config and some +# installation scripts): +# +#%# family=contrib +#%# capabilities=autoconf + +# IMAP Configuration Directory +if [ "$1" = "autoconf" ]; then + echo yes + exit 0 +fi + +declare -A averages=() + +function roundcubemail_logs() { + find /var/log/roundcubemail/ -type f -name "console" -o -name "console-*" -a ! -name "console-*.gz" +} + +function roundcubemail_actions() { + for action in `cat $(roundcubemail_logs) | awk '{print $4}' | grep -E "^[a-z\/]+" | sort | uniq`; do + _action=$(echo ${action} | sed -e 's/\//_/g' -e 's/\./_/g' -e 's/\-/_/g') + echo "${action} ${_action}" + done +} + +function roundcubemail_action_average() { + average=`grep "${1}" $(roundcubemail_logs) | awk '{sum+=$8} END {print sum/NR}' 2>/dev/null` + echo "${average}" +} + +function httpd_log_files() { + find /var/log/httpd/ -type f -name "*access_log" -o -name "*access_log-*" -a ! -name "*access_log-*.gz" +} + +# If run with the "config"-parameter, give out information on how the +# graphs should look. +if [ "$1" = "config" ]; then + echo "multigraph roundcubemail" + echo "graph_args --base 1000 -l 0" + echo "graph_title Action Completion Duration" + echo "graph_args --base 1000 -l 0" + echo "graph_vlabel seconds" + echo "graph_scale no" + echo "graph_category roundcubemail" + echo "graph_info Average times reported on actions." + echo "graph_order $(roundcubemail_actions | while read action _action; do + echo -n " ${_action}=roundcubemail.${_action}.${_action}" + done)" + echo "" + roundcubemail_actions | while read action _action; do + echo "roundcubemail.${_action}.label ${action}" + echo "roundcubemail.${_action}.type GAUGE" + done + echo "" + + roundcubemail_actions | while read action _action; do + echo "multigraph roundcubemail.${_action}" + echo "graph_args --base 1000 -l 0" + echo "graph_title ${action}" + echo "graph_args --base 1000 -l 0" + echo "graph_vlabel seconds" + echo "graph_scale no" + echo "graph_category roundcubemail" + echo "graph_info Average times reported for ${action}." + echo "" + echo "${_action}.label ${action}" + echo "${_action}.type GAUGE" + echo "" + done + echo "" + +# echo "graph_title MSIE HTTP Client Access" +# echo "graph_args --base 1000 -l 0" +# echo "graph_vlabel hits" +# echo "graph_scale no" +# echo "graph_category apache" +# echo "graph_info Number of hits per MSIE version" +# for vernumber in `grep -E "MSIE [0-9]+\.[0-9]+" $(httpd_log_files) | awk '{print $15}' | sort -u | sed -e 's/\.//g' -e 's/;//g'`; do +# graph_order="${graph_order} msie_${vernumber}" +# echo "msie_${vernumber}.label MSIE ${vernumber} % of hits" +# echo "msie_${vernumber}.type GAUGE" +# echo "msie_${vernumber}.info Percentage of hits for MSIE ${vernumber}" +# done + # Last, if run with the "config"-parameter, quit here (don't + # display any data) + exit 0 +fi + +# Gather shit +# declare -a ver +# declare -a num +# +# IFS=$'\n' +# for agent_line in `grep -E "MSIE [0-9]+\.[0-9]+" $(httpd_log_files) | awk '{print $14,$15}' | sort | uniq -c | sed -e 's/\.//g' -e 's/;//g'`; do +# num[${#ver[@]}]=$(echo $agent_line | awk '{print $1}') +# ver[${#ver[@]}]=$(echo $agent_line | awk '{print $3}') +# done +# +# i=0 +# total=0 +# while [ $i -lt ${#num[@]} ]; do +# total=$(( $total + ${num[$i]} )) +# let i++ +# done +# +# i=0 +# while [ $i -lt ${#ver[@]} ]; do +# percentage=$(echo "( ${num[$i]} * 100 ) / $total" | bc) +# echo "msie_${ver[$i]}.value $percentage" +# let i++ +# done +# echo "" + +# roundcubemail_actions +roundcubemail_actions | while read action _action; do + echo "multigraph roundcubemail.${_action}" + echo "${_action}.value $(roundcubemail_action_average "${action}")" + echo "" +done diff --git a/runtime/nagios/check_email_delivery b/runtime/nagios/check_email_delivery new file mode 100755 index 0000000..f1ad2ae --- /dev/null +++ b/runtime/nagios/check_email_delivery @@ -0,0 +1,332 @@ +#!/usr/bin/perl + +use Data::Dumper; +use Nagios::Plugin; +use vars qw($msg $state); + +my $plugin = Nagios::Plugin->new( + usage => "Usage: %s [ -v|--verbose ] [ -h|--help ] [--usage] " + . "[ -c|--critical= ] [ -w|--warning= ] " + . "[ -t|--timeout= ] [--libexec=] " + . "[ -p|--plugins= ] [ -A|--alert= ] ", + + version => "0.1.1", + url => "http://kolab.org/about/nagios-plugins-kolab", + license => "GPLv2+" + ); + +$plugin->add_arg( + spec => "critical|c=i", + help => "Exit with CRITICAL after seconds have passed." + ); + +$plugin->add_arg( + spec => "debug", + help => "Enable debugging." + ); + +$plugin->add_arg( + spec => "hostname|H=s", + help => "Server address to check. Will be used for both IMAP and SMTP " + . "unless either or both are separately specified." + ); + +$plugin->add_arg( + spec => "imap-check-interval=i", + help => "Number of seconds between checks against IMAP to attempt to " + . "find the message." + ); + +$plugin->add_arg( + spec => "imap-mailbox=s", + help => "IMAP mailbox to search for the message." + ); + +$plugin->add_arg( + spec => "imap-password=s", + help => "Password for IMAP specifically." + ); + +$plugin->add_arg( + spec => "imap-port=i", + help => "IMAP port number." + ); + +$plugin->add_arg( + spec => "imap-server=s", + help => "IMAP server address, if different from --hostname." + ); + +$plugin->add_arg( + spec => "imap-starttls", + help => "Use STARTTLS (explicit SSL)" + ); + +$plugin->add_arg( + spec => "imap-username=s", + help => "Username for IMAP specifically." + ); +$plugin->add_arg( + spec => "imap-ssl", + help => "Use SSL (implicit)" + ); + +$plugin->add_arg( + spec => "imap-timeout=i", + help => "IMAP timeout" + ); + +$plugin->add_arg( + spec => "mail-from=s", + help => "Use MAIL FROM address STRING" + ); + +$plugin->add_arg( + spec => "mail-to=s", + help => "Use RCPT TO address STRING" + ); + +$plugin->add_arg( + spec => "mail-subject=s", + help => "Specify mail subject" + ); + +$plugin->add_arg( + spec => "mail-header=s@", + help => "Specify additional mail headers" + ); + +$plugin->add_arg( + spec => "password=s", + help => "Password" + ); + +$plugin->add_arg( + spec => "plugins=s@", + help => "Plugin commands to execute" + ); + +$plugin->add_arg( + spec => "smtp-password=s", + help => "Password" + ); + +$plugin->add_arg( + spec => "smtp-port=i", + help => "SMTP port number" + ); + +$plugin->add_arg( + spec => "smtp-server=s", + help => "SMTP server address, if different from --hostname" + ); + +$plugin->add_arg( + spec => "smtp-starttls", + help => "Use STARTTLS (explicit SSL)" + ); + +$plugin->add_arg( + spec => "smtp-ssl", + help => "Use SSL (implicit)" + ); + +$plugin->add_arg( + spec => "smtp-timeout=i", + help => "SMTP timeout" + ); + +$plugin->add_arg( + spec => "smtp-username=s", + help => "Username" + ); + +$plugin->add_arg( + spec => "ssl", + help => "Use SSL (implicit SSL)" + ); + +$plugin->add_arg( + spec => "starttls", + help => "Use STARTTLS (explicit SSL)" + ); + +$plugin->add_arg( + spec => "username=s", + help => "Username" + ); + +$plugin->add_arg( + spec => "warning|w=i", + help => "Exit with WARNING after seconds have passed." + ); + +$plugin->getopts(); + +## +## Parse options to get to defaults +## + +my $time_start = time; + +# The host address(es) to check +if (!$plugin->opts->hostname) { + $plugin->nagios_exit(ERROR, "No hostname for IMAP specified") + unless $plugin->opts->{'imap-server'}; + + $plugin->nagios_exit(ERROR, "No hostname for SMTP specified") + unless $plugin->opts->{'smtp-server'}; + +} else { + $plugin->opts->{'imap-server'} = $plugin->opts->hostname + unless $plugin->opts->{'imap-server'}; + + $plugin->opts->{'smtp-server'} = $plugin->opts->hostname + unless $plugin->opts->{'smtp-server'}; + + delete $plugin->opts->{'hostname'}; +} + +# SSL or STARTTLS? +if ($plugin->opts->starttls && $plugin->opts->ssl) { + $plugin->nagios_exit(ERROR, "Cannot specify both starttls and ssl"); +} elsif ($plugin->opts->starttls) { + $plugin->opts->{'imap-starttls'} = $plugin->opts->starttls + unless $plugin->opts->{'imap-starttls'}; + + $plugin->opts->{'smtp-starttls'} = $plugin->opts->starttls + unless $plugin->opts->{'smtp-starttls'}; + + delete $plugin->opts->{'starttls'}; +} elsif ($plugin->opts->ssl) { + $plugin->opts->{'imap-ssl'} = $plugin->opts->ssl + unless $plugin->opts->{'imap-ssl'}; + + $plugin->opts->{'smtp-ssl'} = $plugin->opts->ssl + unless $plugin->opts->{'smtp-ssl'}; + + delete $plugin->opts->{'ssl'}; +} + +# Plugin specific timeouts +$plugin->opts->{'imap-timeout'} = $plugin->opts->timeout + unless $plugin->opts->{'imap-timeout'}; + +$plugin->opts->{'smtp-timeout'} = $plugin->opts->timeout + unless $plugin->opts->{'smtp-timeout'}; + +## +## Set our own timeout +## +local $SIG{ALRM} = sub { + $plugin->nagios_exit( + CRITICAL, + "Exceeded " . $plugin->opts->timeout . " seconds timeout" + ); + }; + +alarm $plugin->opts->timeout; + +## +## Check if the plugins exist +## +foreach (@{$plugin->opts->plugins}) { + # Exit if the plugin does not exist. + $plugin->nagios_exit( + ERROR, + "Plugin " . $_ . ": No such file or directory." + ) unless -e $_; + + # Exit if the plugin is not executable. + $plugin->nagios_exit( + ERROR, + "Plugin " . $_ . ": Permission denied." + ) unless -x $_; +} + +## +## Use our options to define the options of the individual plugins +## +my @bool_opts = ( + "debug", + "imap-ssl", + "imap-starttls", + "smtp-ssl", + "smtp-starttls", + "ssl", + "starttls", + "verbose" + ); + +# Map them so we can look them up. +my %bool_opts = map { $_ => 1 } @bool_opts; + +# Placeholder for the return text and return code of each plugin. +my %status; + +foreach my $exec_plugin (@{$plugin->opts->plugins}) { + my $exec_options = ""; + + foreach my $option_key (keys %{$plugin->opts}) { + # Skip attributes internal to GetOpt + next if $option_key =~ /^_/; + + # Skip plugins option + next if $option_key eq "plugins"; + + # Skip undefined options + next unless $plugin->opts->{$option_key}; + + # Skip any extra-opts + next if $option_key eq "extra-opts"; + + # Skip IMAP options for SMTP, and vice-versa. + next if $exec_plugin =~ /_imap_/ and $option_key =~ /smtp/; + next if $exec_plugin =~ /_smtp_/ and $option_key =~ /imap/; + + # Add the option switch, and continue if the option is a boolean + # switch. + $exec_options .= " --" . $option_key and + next if exists($bool_opts{$option_key}); + + # Now map the options that are an array, such as mail-header + if (ref($plugin->opts->{$option_key}) eq "HASH") { + # We don't have these yet... right? + } elsif (ref($plugin->opts->{$option_key}) eq "ARRAY") { + foreach (@{$plugin->opts->{$option_key}}) { + $exec_options .= " --" . $option_key . "='" . $_ . "'"; + } + } else { + $exec_options .= " --" + . $option_key + . "='" + . $plugin->opts->{$option_key} + . "'"; + + } + } + + $status{$exec_plugin}{'result'} = `$exec_plugin $exec_options`; + $status{$exec_plugin}{'return'} = $?; +} + +my $time_end = time; + +foreach my $exec_plugin (@{$plugin->opts->plugins}) { + # Exit with the status of the plugin that failed -- if any. + $plugin->nagios_exit( + $status{$exec_plugin}{'return'}, + $status{$exec_plugin}{'result'} + ) unless $status{$exec_plugin}{'return'} == 0; + + if ($plugin->opts->verbose) { + print $status{$exec_plugin}{'result'}; + } +} + +my $duration = ($time_end - $time_start); + +$plugin->nagios_exit( + OK, + "Message sent, delivered and received in " . $duration . " second(s)" + ); diff --git a/runtime/nagios/check_imap_receive b/runtime/nagios/check_imap_receive new file mode 100755 index 0000000..31ae255 --- /dev/null +++ b/runtime/nagios/check_imap_receive @@ -0,0 +1,289 @@ +#!/usr/bin/perl + +use Data::Dumper; +use Nagios::Plugin; +use vars qw($msg $state); + +my $plugin = Nagios::Plugin->new( + usage => "Usage: %s [ -v|--verbose ] [ -h|--help ] [--usage] " + . "[ -c|--critical= ] [ -w|--warning= ] " + . "[ -t|--timeout= ] [--libexec=] " + . "[ -p|--plugins= ] [ -A|--alert= ] ", + + version => "0.1.1", + url => "http://kolab.org/about/nagios-plugins-kolab", + license => "GPLv2+" + ); + +$plugin->add_arg( + spec => "critical|c=i", + help => "Exit with CRITICAL after seconds have passed." + ); + +$plugin->add_arg( + spec => "debug", + help => "Enable debugging." + ); + +$plugin->add_arg( + spec => "hostname|imap-server|H=s", + help => "IMAP server address" + ); + +$plugin->add_arg( + spec => "imap-check-interval=i", + help => "Number of seconds between checks" + ); + +$plugin->add_arg( + spec => "imap-mailbox=s", + help => "IMAP mailbox to search for the message." + ); + +$plugin->add_arg( + spec => "imap-port=i", + help => "IMAP port number" + ); + +$plugin->add_arg( + spec => "imap-timeout=i", + help => "IMAP timeout" + ); + +$plugin->add_arg( + spec => "mail-from=s", + help => "Use MAIL FROM address STRING" + ); + +$plugin->add_arg( + spec => "mail-to=s", + help => "Use RCPT TO address STRING" + ); + +$plugin->add_arg( + spec => "mail-subject=s", + help => "Specify mail subject" + ); + +$plugin->add_arg( + spec => "mail-header=s@", + help => "Specify additional mail headers" + ); + +$plugin->add_arg( + spec => "password|imap-password|P=s", + help => "Password" + ); + +$plugin->add_arg( + spec => "ssl|imap-ssl", + help => "Use SSL (implicit SSL)" + ); + +$plugin->add_arg( + spec => "starttls|imap-starttls", + help => "Use STARTTLS (explicit SSL)" + ); + +$plugin->add_arg( + spec => "username|imap-username|U=s", + help => "Username" + ); + +$plugin->add_arg( + spec => "warning|w=i", + help => "Exit with WARNING after seconds have passed." + ); + +$plugin->getopts(); + +# print Dumper($plugin->opts) . "\n"; + +## +## Parse options to get to defaults +## + +my $time_start = time; + +# The host address(es) to check +if (!$plugin->opts->hostname) { + $plugin->nagios_exit(ERROR, "No hostname for IMAP specified") + unless $plugin->opts->{'imap-server'}; + +} else { + $plugin->opts->{'imap-server'} = $plugin->opts->hostname + unless $plugin->opts->{'imap-server'}; + + delete $plugin->opts->{'hostname'}; +} + +# SSL or STARTTLS? +if ($plugin->opts->starttls && $plugin->opts->ssl) { + $plugin->nagios_exit(ERROR, "Cannot specify both starttls and ssl"); +} elsif ($plugin->opts->starttls) { + $plugin->opts->{'imap-starttls'} = $plugin->opts->starttls + unless $plugin->opts->{'imap-starttls'}; + + $plugin->opts->{'imap-port'} = 143 unless $plugin->opts->{'imap-port'}; + delete $plugin->opts->{'starttls'}; +} elsif ($plugin->opts->ssl) { + $plugin->opts->{'imap-ssl'} = $plugin->opts->ssl + unless $plugin->opts->{'imap-ssl'}; + + $plugin->opts->{'imap-port'} = 993 unless $plugin->opts->{'imap-port'}; + delete $plugin->opts->{'ssl'}; +} + +# Plugin specific timeouts +$plugin->opts->{'imap-timeout'} = $plugin->opts->timeout + unless $plugin->opts->{'imap-timeout'}; + +if ($plugin->opts->username) { + $plugin->opts->{'imap-username'} = $plugin->opts->username + unless $plugin->opts->{'imap-username'}; +} + +if ($plugin->opts->password) { + $plugin->opts->{'imap-password'} = $plugin->opts->password + unless $plugin->opts->{'imap-password'}; +} + +$plugin->opts->{'imap-check-interval'} = 1 + unless $plugin->opts->{'imap-check-interval'}; + +if ($plugin->opts->{'imap-ssl'} or $plugin->opts->{'imap-starttls'}) { + eval "require IO::Socket::SSL"; + $plugin->nagios_exit(ERROR, "Could not load IO::Socket::SSL") if $@; + require IO::Socket::SSL; + + eval "require IO::Socket"; + $plugin->nagios_exit(ERROR, "Could not load IO::Socket") if $@; + require IO::Socket; +} + +eval "require Mail::IMAPClient"; +$plugin->nagios_exit(ERROR, "Could not load Mail::IMAPClient") if $@; +require Mail::IMAPClient; + +## +## Set our own timeout +## +local $SIG{ALRM} = sub { + $plugin->nagios_exit( + CRITICAL, + "Exceeded " . $plugin->opts->timeout . " seconds timeout" + ); + + }; + +alarm $plugin->opts->timeout; + +my $imap = Mail::IMAPClient->new( + Authmechanism => "LOGIN", + Debug => $plugin->opts->debug + ); + +my @sslargs = ( SSL_verify_mode => 0 ); + +if ($plugin->opts->{'imap-ssl'}) { + $imap->connect( + Ssl => \@sslargs, + Server => $plugin->opts->{'imap-server'}, + Port => $plugin->opts->{'imap-port'}, + Debug => $plugin->opts->debug + ); +} elsif ($plugin->opts->{'imap-starttls'}) { + $imap->connect( + Starttls => \@sslargs, + Server => $plugin->opts->{'imap-server'}, + Port => $plugin->opts->{'imap-port'}, + Debug => $plugin->opts->debug + ); +} else { + $imap->connect( + Server => $plugin->opts->{'imap-server'}, + Port => $plugin->opts->{'imap-port'}, + Debug => $plugin->opts->debug + ); +} + +$imap->State(Mail::IMAPClient->Connected); +$imap->User($plugin->opts->{'imap-username'}); +$imap->Password($plugin->opts->{'imap-password'}); +$imap->login() or $plugin->nagios_exit(CRITICAL, "Cannot login: $@"); + +$imap->Peek(1) if $peek; +$imap->Ignoresizeerrors(1); + +my $mailbox = $plugin->opts->{'imap-mailbox'} || "INBOX"; + +my @search_args = (); + +if ($plugin->opts->{'mail-from'}) { + push @search_args, "FROM" => $plugin->opts->{'mail-from'}; +} + +if ($plugin->opts->{'mail-to'}) { + push @search_args, "TO" => $plugin->opts->{'mail-to'}; +} + +if ($plugin->opts->{'mail-subject'}) { + push @search_args, "SUBJECT" => $plugin->opts->{'mail-subject'}; +} + +my %header_search = (); + +if ($plugin->opts->{'mail-header'}) { + foreach (@{$plugin->opts->{'mail-header'}}) { + my ($h_name, $h_value) = split(/: /, $_); + $header_search{$h_name} = $h_value; + + } + + push @search_args, ( "HEADER" => %header_search ); +} + +my $tries = 0; +my $max_retries = 10; +my @msgs; + +until( scalar(@msgs) != 0 || $tries >= $max_retries ) { + eval { + $imap->select($mailbox) or + $plugin->nagios_exit( + CRITICAL, + "Cannot SELECT " . $mailbox . ": $@" + ); + + @msgs = $imap->search(@search_args); + $plugin->nagios_exit(UNKNOWN, "Invalid search parameters: $@") if $@; + }; + + $tries++; + sleep $plugin->opts->{'imap-check-interval'} unless + (scalar(@msgs) != 0 || $tries >= $max_retries); +} + +if (scalar(@msgs) > 0) { + $imap->set_flag("Seen", @msgs); +} + +$imap->delete_message(scalar($imap->seen)) + or warn "Could not delete messages: $@\n"; + +$imap->expunge($mailbox); + +my $time_end = time; + +if (scalar(@msgs) > 1) { + $plugin->nagios_exit(UNKNOWN, "More than one message found."); +} elsif (scalar(@msgs) < 1) { + $plugin->nagios_exit(CRITICAL, "No messages found."); +} else { + my $duration = ($time_end - $time_start); + + $plugin->nagios_exit( + OK, + "1 message delivered and found in " . $duration . " second(s)." + ); +} diff --git a/runtime/nagios/check_kernel_status b/runtime/nagios/check_kernel_status new file mode 100644 index 0000000..200e141 --- /dev/null +++ b/runtime/nagios/check_kernel_status @@ -0,0 +1,108 @@ +#!/usr/bin/perl +# check_kernel_status : check if the running kernel is the latest installed +# By Toni Van Remortel [toni.van.remortel@p-ops.be] +# 2008-07-28 +# GPLv2 + +$OK = 0; +$WARN = 1; +$CRIT = 2; +$UNKN = 3; + +# First, find the current running kernel version +if ( -e '/proc/version_signature' ) +{ + # Likely Ubuntu + $sig = `cat /proc/version_signature`; + if ( $sig =~ /.* (\d+)\.(\d+)\.(\d+)-(\d+)\.(\d+)-[generic|server]/ ) + { + @running_version = ($1, $2, $3, $4, $5); + } + else + { + print "UNKNOWN - Cannot find running Ubuntu kernel version\n"; + exit $UNKN; + } +} +elsif ( -e '/proc/version' ) +{ + # Likely Debian + $sig = `cat /proc/version`; + if ( $sig =~ /\(Debian (\d+)\.(\d+)\.(\d+)\.dfsg\.(\d+)-(\d+)\)/ + || $sig =~ /\(Debian (\d+)\.(\d+)\.(\d+)\.dfsg\.(\d+)-(\d+)\w+(\d+)\)/ + || $sig =~ /\(Debian (\d+)\.(\d+)\.(\d+)-(\d+).+?(\d+).+?(\d+)\)/ + || $sig =~ /\(Debian (\d+)\.(\d+)\.(\d+)-(\d+)lenny(\d+)\)/ + ) + { + @running_version = ($1, $2, $3, $4, $5, $6); + } + else + { + print "UNKNOWN - Cannot find running Debian kernel version\n"; + exit $UNKN; + } +} +else +{ + print "UNKNOWN - Cannot extract running kernel info\n"; + exit $UNKN; +} + +# Next, find the installed kernel version +# Yes, as you can see, it is limited to 2.6 kernels here. +# But I assume that you don't need reboots anymore when this major version has passed. +$dpkg_list = `dpkg -l | grep linux-image-2.6`; +chomp($dpkg_list); +@dpkg_lines = split("\n", $dpkg_list); +$dpkg = pop(@dpkg_lines); + +# Now, which OS is it, and which footprint do they use? +if ( $dpkg =~ /(\d+)\.(\d+)\.(\d+)-(\d+)\.(\d+)/ ) +{ + # Ubuntu + @installed_version = ($1, $2, $3, $4, $5, 0); +} +elsif ( $dpkg =~ /(\d+)\.(\d+)\.(\d+)\.dfsg\.(\d+)-(\d+)\w+(\d+)/ ) +{ + # Debian Etch and older + @installed_version = ($1, $2, $3, $4, $5, $6); +} +elsif ( $dpkg =~ /(\d+)\.(\d+)\.(\d+)\.dfsg\.(\d+)-(\d+) / ) +{ + # Debian Etch and older + @installed_version = ($1, $2, $3, $4, $5, 0); +} +elsif ( $dpkg =~ /(\d+)\.(\d+)\.(\d+)-(\d+)\~.+?(\d+).+?(\d+)/ ) +{ + # Debian Etch and older + @installed_version = ($1, $2, $3, $4, $5, $6); +} +elsif ( $dpkg =~ /Debian (\d+)\.(\d+)\.(\d+)\+(\d+)\+lenny(\d+)/ ) +{ + # Debian Lenny + @installed_version = ($1, $2, $3, $4, $5, 0); +} +else +{ + print "UNKNOWN - Could not determine installed version.\n"; + exit $UNKN; +} + +# Calculate sums for easy comparison +$running_version_sum = sprintf("%02d%02d%02d%02d%02d%02d", @running_version); +$installed_version_sum = sprintf("%02d%02d%02d%02d%02d%02d", @installed_version); +# And some readable format +$print_running_version = sprintf("%d.%d.%d-%d.%d.%d", @running_version); +$print_installed_version = sprintf("%d.%d.%d-%d.%d.%d", @installed_version); + +# Do we need a reboot? +if ( $running_version_sum < $installed_version_sum ) +{ + print "WARNING - Reboot required : running kernel = $print_running_version, installed kernel = $print_installed_version\n"; + exit $WARN; +} +else +{ + print "OK - running kernel = $print_running_version, installed kernel = $print_installed_version\n"; + exit $OK; +} diff --git a/runtime/nagios/check_saslauthd b/runtime/nagios/check_saslauthd new file mode 100755 index 0000000..669693a --- /dev/null +++ b/runtime/nagios/check_saslauthd @@ -0,0 +1,40 @@ +#! /usr/bin/perl -w + +use Nagios::Plugin; + +use vars qw($msg $state); + +my $plugin = Nagios::Plugin->new( + usage => "Usage: %s [ -v|--verbose ] [-H ] [-t ] " + . "[ -c|--critical= ] [ -w|--warning= ] " + . "[ -u|--user= ] [ -p|--password= ]" + ); + +$plugin->add_arg( + spec => "user|u=s", + help => "-u, --user=STRING . Username to use." + ); + +$plugin->add_arg( + spec => "password|p=s", + help => "-p, --password=STRING . Password to use." + ); + +$plugin->getopts(); + +my $result = system( + "/usr/sbin/testsaslauthd" + . " -u " . $plugin->opts->user + . " -p " . $plugin->opts->password + . " > /dev/null 2>&1" + ); + +if ($result) { + $msg = "CRITICAL: authentication failed for " . $plugin->opts->user; + $state = CRITICAL; +} else { + $msg = "OK: authentication for " . $plugin->opts->user . " successful"; + $state = OK; +} + +$plugin->nagios_exit($state, $msg); diff --git a/runtime/nagios/check_service_ip b/runtime/nagios/check_service_ip new file mode 100755 index 0000000..d1e47d1 --- /dev/null +++ b/runtime/nagios/check_service_ip @@ -0,0 +1,55 @@ +#! /usr/bin/perl -w + +use Data::Dumper; +use Nagios::Plugin; + +use vars qw($msg $state); + +my $plugin = Nagios::Plugin->new( + usage => "Usage: %s [ -v|--verbose ] [-H ] [-t ] " +# . "[ -c|--critical= ] [ -w|--warning= ] " + . "[ --expect= ]" + ); + +$plugin->add_arg( + spec => "expect=s@", + help => "Expect the host to have the specified IP address configured." + ); + +$plugin->add_arg( + spec => "interface|i=s", + help => "Interface to compare addresses of." + ); + +$plugin->getopts(); + +my $interface; + +if (!$plugin->opts->interface) { + $interfaces = `ifconfig | grep -vE "^(\\s+|\$|lo)" | awk -F':' '{print \$1}' | awk '{print \$1}' | head -n 1`; + $interfaces =~ s/\s*//g; + $interface = $interfaces; +} else { + $interface = $plugin->opts->interface; +} + +my $result = `ip addr sh $interface | awk '/inet /' | awk '/scope global secondary /' | awk '{print \$2}' 2>/dev/null`; + +my @ips = split('\n',$result); + +print "IPs: " . Dumper(@ips) . "\n"; + +foreach $ip (@ips) { + if ($ip eq "" ) { + $plugin->nagios_exit(CRITICAL, "No Service IP Address"); + } elsif (!$plugin->opts->expect) { + $plugin->nagios_exit(OK, "Service IP Address $ip"); + } else { + foreach (@{$plugin->opts->expect}) { + if ($ip eq $_) { + $plugin->nagios_exit(OK, "Service IP Address $_ in $ip"); + } + } + } +} +$plugin->nagios_exit($state, $msg); diff --git a/runtime/nagios/check_smtp_send b/runtime/nagios/check_smtp_send new file mode 100755 index 0000000..42a7df5 --- /dev/null +++ b/runtime/nagios/check_smtp_send @@ -0,0 +1,245 @@ +#!/usr/bin/perl + +use Data::Dumper; +use Nagios::Plugin; +use POSIX qw(strftime); +use vars qw($msg $state); + +my $plugin = Nagios::Plugin->new( + usage => "Usage: %s [ -v|--verbose ] [ -h|--help ] [--usage] " + . "[ -c|--critical= ] [ -w|--warning= ] " + . "[ -t|--timeout= ] ", + + version => "0.1.1", + url => "http://kolab.org/about/nagios-plugins-kolab", + license => "GPLv2+" + ); + +$plugin->add_arg( + spec => "critical|c=i", + help => "Exit with CRITICAL after seconds have passed." + ); + +$plugin->add_arg( + spec => "debug", + help => "Enable debugging." + ); + +$plugin->add_arg( + spec => "hostname|H=s", + help => "Server address to check" + ); + +$plugin->add_arg( + spec => "mail-from=s", + help => "Use MAIL FROM address STRING" + ); + +$plugin->add_arg( + spec => "mail-to=s", + help => "Use RCPT TO address STRING" + ); + +$plugin->add_arg( + spec => "mail-subject=s", + help => "Specify mail subject" + ); + +$plugin->add_arg( + spec => "mail-header=s@", + help => "Specify additional mail headers" + ); + +$plugin->add_arg( + spec => "password|smtp-password|P=s", + help => "Password" + ); + +$plugin->add_arg( + spec => "smtp-port=i", + help => "SMTP port number" + ); + +$plugin->add_arg( + spec => "smtp-server=s", + help => "SMTP server address, if different from --hostname" + ); + +$plugin->add_arg( + spec => "smtp-timeout=i", + help => "SMTP timeout" + ); + +$plugin->add_arg( + spec => "ssl|smtp-ssl", + help => "Use SSL (implicit SSL)" + ); + +$plugin->add_arg( + spec => "starttls|smtp-starttls", + help => "Use STARTTLS (explicit SSL)" + ); + +$plugin->add_arg( + spec => "username|smtp-username|U=s", + help => "Username" + ); + +$plugin->add_arg( + spec => "warning|w=i", + help => "Exit with WARNING after seconds have passed." + ); + +$plugin->getopts(); + +# print Dumper($plugin->opts) . "\n"; + +## +## Parse options to get to defaults +## + +my $time_start = time; + +# The host address(es) to check +if (!$plugin->opts->hostname) { + $plugin->nagios_exit(ERROR, "No hostname for SMTP specified") + unless $plugin->opts->{'smtp-server'}; + +} else { + $plugin->opts->{'smtp-server'} = $plugin->opts->hostname + unless $plugin->opts->{'smtp-server'}; + + delete $plugin->opts->{'hostname'}; +} + +# SSL or STARTTLS? +if ($plugin->opts->starttls && $plugin->opts->ssl) { + $plugin->nagios_exit(ERROR, "Cannot specify both starttls and ssl"); +} elsif ($plugin->opts->starttls) { + $plugin->opts->{'smtp-starttls'} = $plugin->opts->starttls + unless $plugin->opts->{'smtp-starttls'}; + + delete $plugin->opts->{'starttls'}; +} elsif ($plugin->opts->ssl) { + $plugin->opts->{'smtp-ssl'} = $plugin->opts->ssl + unless $plugin->opts->{'smtp-ssl'}; + + delete $plugin->opts->{'ssl'}; +} + +# Plugin specific timeouts +$plugin->opts->{'smtp-timeout'} = $plugin->opts->timeout + unless $plugin->opts->{'smtp-timeout'}; + +if ($plugin->opts->username) { + $plugin->opts->{'smtp-username'} = $plugin->opts->username + unless $plugin->opts->{'smtp-username'}; + +} + +if ($plugin->opts->password) { + $plugin->opts->{'smtp-password'} = $plugin->opts->password + unless $plugin->opts->{'smtp-password'}; + +} + +if ($plugin->opts->{'smtp-ssl'} or $plugin->opts->{'smtp-starttls'}) { + eval "require Net::SMTP::SSL"; + $plugin->nagios_exit(ERROR, "Could not load Net::SMTP::SSL") if $@; + require Net::SMTP::SSL; +} + +if ($plugin->opts->{'smtp-username'}) { + eval "require Authen::SASL"; + $plugin->nagios_exit(ERROR, "Could not load Authen::SASL") if $@; +} + +## +## Set our own timeout +## +local $SIG{ALRM} = sub { + $plugin->nagios_exit( + CRITICAL, + "Exceeded " . $plugin->opts->timeout . " seconds timeout" + ); + + }; + +alarm $plugin->opts->timeout; + +require Net::SMTP; + +# Connect to SMTP +$smtp = Net::SMTP->new( + $plugin->opts->{'smtp-server'}, + Port => $plugin->opts->{'smtp-port'}, + Timeout => $plugin->opts->{'smtp-timeout'}, + Debug => $plugin->opts->debug + ); + +if ($plugin->opts->{'smtp-ssl'}) { + $smtp = Net::SMTP::SSL->start_SSL( + $smtp, + SSL_verify_mode => SSL_VERIFY_NONE + ); + $plugin->nagios_exit(CRITICAL, "Could not start TLS") + unless $smtp->code == 220; + +} elsif ($plugin->opts->{'smtp-starttls'}) { + $smtp->command('STARTTLS'); + $smtp->response(); + $plugin->nagios_exit(CRITICAL, "Could not start TLS") + unless $smtp->code == 220; + + $smtp = Net::SMTP::SSL->start_SSL( + $smtp, + SSL_verify_mode => SSL_VERIFY_NONE + ); + + $smtp->hello(); +} + +if ($plugin->opts->{'smtp-username'} && $plugin->opts->{'smtp-password'}) { + $smtp->auth( + $plugin->opts->username, + $plugin->opts->password + ); +} + +$smtp->mail($plugin->opts->{'mail-from'}); +$smtp->to($plugin->opts->{'mail-to'}); +$smtp->data(); +$smtp->datasend("Subject: " . $plugin->opts->{'mail-subject'} . "\n"); +$smtp->datasend(rfc2822_date() . "\n"); +$smtp->datasend(rfc2822_msgid() . "\n"); +$smtp->datasend("To: " . $plugin->opts->{'mail-to'} . "\n"); +$smtp->datasend("From: " . $plugin->opts->{'mail-from'} . "\n"); + +foreach (@{$plugin->opts->{'mail-header'}}) { + $smtp->datasend("$_\n"); +} + +$smtp->datasend("\n"); +$smtp->datasend("This is a message\n"); +$smtp->dataend(); +$smtp->quit(); + +my $time_end = time; + +$plugin->nagios_exit( + OK, + "Message sent in " . ($time_end - $time_start) . " second(s)." + ); + +# RFC 2822 date +sub rfc2822_date { + return strftime("Date: %a, %e %b %Y %H:%M:%S %z (%Z)", gmtime); +} + +# RFC 2822 message id +sub rfc2822_msgid { + my $hostname = `hostname`; + chomp $hostname; + return "Message-ID: <" . rand(0xffffffff) . ".nagios@" . $hostname . ">"; +} +