Appendix F. Example monitoring scripts

This appendix lists the code for the three monitoring scripts mentioned previously.

Example F-1. Testing an SMTP transaction against the localhost.


#!/usr/bin/perl -w
#
# Run a complete test SMTP transaction against the localhost, using the
# special domain smtp-test.org.
#
# This will not be run if the system is closed due to load, but will otherwise
# allow us to know if the system is broken
#
# Steve
# --
#



use strict;
use warnings;


use IO::Socket;




#
#  Interactive run?  If so we'll show output.
#
my $verbose = 0;
$verbose = 1
  if (    ( defined( $ENV{ 'TERM' } ) )
       && ( length( $ENV{ 'TERM' } ) ) );


#
# Exit if we're too loaded.
#
if ( -e "/tmp/loaded" )
{
    $verbose && print "Machine loaded: skipping test\n";
    exit;
}

#
#  Get the socket.
#
eval {
    local $SIG{ ALRM } = sub {die "alarm\n"};    # NB: \n required
    alarm 60;

    my $socket = IO::Socket::INET->new(
                                        PeerAddr => "localhost",
                                        PeerPort => 25,
                                        Proto    => "tcp",
                                        Type     => SOCK_STREAM
    ) or die "Couldn't connect to localhost:25 $@\n";


    #
    # wait for greeting.
    #
    my $greet = <$socket> || "";
    chomp($greet) if ( defined($greet) );
    $verbose && print $greet . "\n";

    #
    # send: helo
    #
    print $socket "helo my.smtp.test\n";
    $verbose && print "helo my.smtp.test\n";

    #
    # get response
    #
    my $answer = <$socket> || "";
    $verbose && print $answer;

    #
    # send: mail from
    #
    print $socket "mail from: <steve\@smtp-test.org>\n";
    $verbose && print "mail from: <steve\@smtp-test.org>\n";

    #
    # get response
    #
    $answer = <$socket> || "";
    $verbose && print $answer;

    #
    # send: rcpt to
    #
    print $socket "rcpt to: <steve\@smtp-test.org>\n";
    $verbose && print "rcpt to: <steve\@smtp-test.org>\n";

    #
    # get response
    #
    $answer = <$socket> || "";
    $verbose && print $answer;

    #
    # send: quit
    #
    print $socket "quit\n";
    $verbose && print "quit\n";

    #
    # get response
    #
    $answer = <$socket> || "";
    $verbose && print $answer;
    close($socket);
};
if ($@)
{
    if ( $@ eq "alarm\n" )
    {
        $verbose && print "Restarting due to timeout\n";
        system("/etc/init.d/qpsmtpd restart >/dev/null");
    }
    else
    {
        $verbose && print "Restarting due to error: $@\n";
        system("/etc/init.d/qpsmtpd restart >/dev/null");
    }
}
  

Example F-2. Throttling back when under a high load.


#!/usr/bin/perl -w
#
#  This script is designed to disable incoming connections when
# the load is "too high".
#
# Steve
# --
#


use strict;
use warnings;
use Sys::CpuLoad;


#
#  When loaded we'll add a new iptables rule to deny new connections.
#
my $busy = "/sbin/iptables -I INPUT -p tcp -i eth0 -m state --state NEW --dport 25 -j REJECT";

#
#  When not loaded we'll re-run our main firewall, at /firewall, which
# will re-allow incoming connections.
#
my $ok   = "/firewall";

#
#  Maximum load we operate with.
#
my $max  = 5;



#
#  The temporary file
#
my $file = "/tmp/loaded";


#
#  Get the uptime
#
my @loads = Sys::CpuLoad::load();
my $load  = int( $loads[0] );

#
#  The machine is currently loaded
#
if ( -e $file )
{
    #
    #  If the load is now dropped then we're fine.
    #
    if ( $load <= 1 )
    {
        #
        #  Remove marker
        #
        unlink($file);
        system( $ok );

        print "Load dropped to $load - restoring service.\n"
          if ( -e "/etc/noisy" );
    }

}
else
{
    #
    #  File doesn't exist
    #
    if ( $load >= $max )
    {
        #
        #  But the load is high.
        #
        open( FILE, ">", $file );
        print FILE "now";
        close(FILE);

        #
        #  Stop the new connections
        #
        system( $busy );
        print "Load risen to $load preventing new connections\n"
          if ( -e "/etc/noisy" );
    }
}

  

Example F-3. Avoiding orphaned qpsmtpd processes.


#!/bin/sh
#
#  Ensure we don't have qpsmtpd processes stuck in a "timedout" state.
#
#  This used to happen prior to 1.4x.x but the tests have been left in
# place just in case.
#
#


#
#  If we're loaded then we'll not care about them.
#
if [ -e /tmp/loaded ]; then
    exit
fi


#
#  Restart if we see them.
#
if ( ps -ef | grep forkserver | grep -i "connection timed out" 2>/dev/null >/dev/null) ;  then
    /etc/init.d/qpsmtpd restart
fi