| Net-Peep documentation | Contained in the Net-Peep distribution. |
Net::Peep::Notifier - Utility object for Peep client event or state e-mail notifications
use Net::Peep::Notifier;
$notifier = new Net::Peep::Notifier;
$notifier->client('logparser'); # identify who is generating notifications
$notifier->from($from); # identify who is sending the e-mail
$notifier->recipients(@recipients); # identify some failsafe recipients
$notifier->relays(@relays); # identify some SMTP relays
$notifier->notify(); # sends an e-mail if it is time, otherwise caches
# the information for sending later
$john = new Net::Peep::Notifier;
$john->flush(); # flush (send) outstanding messages as necessary
Utility object for notifications; for example, when logparser
matches a root login in /var/log/messages.
When a notification is created, the object will first check
whether a notification has been sent for that client (based on the
value of $NOTIFICATION_INTERVAL).
If so, the notification information is merely noted and no
notification is sent out. If not, the notification information,
as well as any previously unsent notification information, is sent
to the recipients specified by return value of the recipients()
method.
The object also supports a flush method, which can be used to
periodically flush (send out) any failsafe messages which are due
to be sent.
The basic idea is to populate the object attributes with pertinant
information (e.g., a a list of recipients, a set of SMTP relays, a
'From:' address, etc.), then call the notify method. If a
notification should be sent, it will be. If not, the information
will be cached for later use (e.g., a call to the flush() method.)
To flush out unsent messages, simply instantiate a new
Net::Peep::Notifier object and call the flush method.
None by default.
$LOGGER - A Net::Peep::Log object
$NOTIFICATIONS - Used for caching failsafe information
$NOTIFICATION_INTERVAL - Number of seconds between each
notification
$NOTIFICATION_LEVEL - A hash whose keys are client names (e.g.,
'logparser') and whose values are the level ('info', 'warn', or
'crit') at which to issue notifications for that client. Defaults
to 'info'.
%NOTIFICATION_RECIPIENTS - A hash whose keys are client names
(e.g., 'logparser') and whose values are arrays of e-mail
addresses to which notifications will be sent for that client.
Will be set to whatever is specified in the Peep configuration
file.
@SMTP_RELAYS - An array of SMTP servers from which e-mail
notifications may be relayed. Defaults to localhost. Will we set
to whatever is specified in the Peep configuration file.
new() - The constructor
from() - A get/set method to store a 'From:' address for e-mail
notification. Must be set prior to calling the notify() method.
interval() - A get/set method to store the notification interval
(in seconds). Defaults to $NOTIFICATION_INTERVAL.
recipients() - A get/set method to store an array of e-mail
recipients. Must be set prior to calling the notify() method.
relays() - A get/set method to store an array of SMTP relays.
Must be set prior to calling the notify() method.
notify() - If applicable, notify recipients of an event or state
via e-mail based on attributes such as generator() etc. (see
above). Otherwise, store the information for later reference.
flush() - Clear out any unsent failsafe messages which have not
been sent in at least $NOTIFICATION_INTERVAL seconds
force() - Forcibly clear out any unsent failsafe messages whether
or not they have been sent in at least $NOTIFICATION_INTERVAL
seconds
Collin Starkweather <collin.starkweather@colorado.edu> Copyright (C) 2001
perl(1), Net::Peep, Net::Peep::Mail
| Net-Peep documentation | Contained in the Net-Peep distribution. |
package Net::Peep::Notifier; require 5.005; use strict; use Carp; use Sys::Hostname; use Data::Dumper; use Net::Peep::Log; use Net::Peep::Mail; require Exporter; use vars qw{ @ISA %EXPORT_TAGS @EXPORT_OK @EXPORT $VERSION $LOGGER $NOTIFICATIONS $NOTIFICATION_INTERVAL %NOTIFICATION_LEVEL %NOTIFICATION_RECIPIENTS %NOTIFICATION_HOSTS @SMTP_RELAYS $HOSTNAME $USER $FROM }; @ISA = qw(Exporter); %EXPORT_TAGS = ( ); @EXPORT_OK = ( ); @EXPORT = qw( ); $VERSION = do { my @r = (q$Revision: 1.1 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r }; $LOGGER = Net::Peep::Log->new(); $NOTIFICATIONS = {}; # used for caching failsafe information $NOTIFICATION_INTERVAL = 1800; # seconds %NOTIFICATION_LEVEL = ( ); # see below for more information %NOTIFICATION_RECIPIENTS = ( ); %NOTIFICATION_HOSTS = ( ); @SMTP_RELAYS = ( 'localhost' ); $HOSTNAME = hostname() ? hostname() : 'localhost'; $USER = $ENV{'USER'} ? $ENV{'USER'} : 'peep'; $FROM = "Peep Notification <$USER\@$HOSTNAME>"; sub new { my $self = shift; my $class = ref($self) || $self; my $this = {}; bless $this, $class; } # end sub new sub _timeToSend { # answers the question: based on the time that the last # notification was sent, is it time to send another notification my $self = shift; my $client = shift; my $last_send_time; if ($self->_sendTimeExists($client)) { $last_send_time = $self->_getSendTime($client); } else { return 1; # if there is no send time, it's time! } my $time = time(); if ($time - $last_send_time > $NOTIFICATION_INTERVAL) { return 1; } else { return 0; } } # end sub _timeToSend sub _notificationExists { # returns 1 if a notification has been sent for a client of the # type stored in the generator object, 0 otherwise my $self = shift; my $client = shift || confess "client not found"; if (exists $NOTIFICATIONS->{$client}) { return 1; } else { return 0; } } # end sub _notificationExists sub _getNotificationRecipients { my $self = shift; my $client = shift || confess "client not found"; unless (exists $NOTIFICATION_RECIPIENTS{$client}) { return wantarray ? () : []; } return wantarray ? @{$NOTIFICATION_RECIPIENTS{$client}} : $NOTIFICATION_RECIPIENTS{$client}; } # end sub _getNotificationRecipients sub _getNotificationHosts { my $self = shift; my $client = shift || confess "client not found"; unless (exists $NOTIFICATION_HOSTS{$client}) { return wantarray ? () : []; } return wantarray ? @{$NOTIFICATION_HOSTS{$client}} : $NOTIFICATION_HOSTS{$client}; } # end sub _getNotificationHosts sub notify { my $self = shift; my $notification = shift || confess "notification not found"; my $force = shift; my $client = $notification->client() || confess "client not found"; if (exists $NOTIFICATION_HOSTS{$client} && exists $NOTIFICATION_RECIPIENTS{$client} && exists $NOTIFICATION_LEVEL{$client}) { unless (scalar($self->_getNotificationRecipients($client))) { $LOGGER->debug(1,"Cannot notify recipients for client [$client]: ". "No recipients were specified."); return 0; } my @hosts = $self->_getNotificationHosts($client); unless (scalar(@hosts)) { $LOGGER->debug(1,"Cannot notify recipients for client [$client]: ". "No acceptable notification hosts [@hosts] were specified."); return 0; } my $ok = 0; for my $host (@hosts) { $LOGGER->debug(8,"Checking host [$host] against hostname [$HOSTNAME] ...\n"); $ok++ if $host eq $HOSTNAME; $ok++ if $host =~ /^(all|localhost|127\.0\.0\.1)$/; $ok = 0, last if $host eq 'none'; } my $status = $notification->status(); if ($NOTIFICATION_LEVEL{$client} eq 'crit' && $status ne 'crit') { $LOGGER->debug(1,"Notification ignored: Notification level is [$status]. ". "Notifications are only sent at [crit]."); return 1; } elsif ($NOTIFICATION_LEVEL{$client} eq 'warn' && $status !~ /^(warn|crit)$/) { $LOGGER->debug(1,"Notification ignored: Notification level is [$status]. ". "Notifications are only sent at [crit] or [warn]."); return 1; } else { # do nothing } my $return; if ($ok) { eval { confess "Cannot notify recipients: No client was specified." unless $client; confess "Cannot notify recipients: No mail relays were specified." unless scalar(@SMTP_RELAYS); $self->store($notification); if ($self->_notificationExists($client)) { if ($self->_timeToSend($client) || $force) { $return = $self->_notify($client); } else { $return = 1; } } else { $return = $self->_notify($client); } }; if ($@ || ! $return) { $LOGGER->log(ref($self),": Error generating notification: $@"); } return $return; } else { $LOGGER->debug(1,"Notification ignored: [$HOSTNAME] was not among the list of acceptable notification hosts."); return 1; } } else { $LOGGER->debug(1,"Notification ignored: No notification information is available for client [$client].\n". "\t(Possibly because no notification block was defined for the client in the Peep \n". "\tconfiguration file.)"); return 1; } } # end sub notify sub _notify { # notify the recipients of the notification my $self = shift; my $client = shift || confess "client not found"; if (scalar($self->_getNotifications($client))) { my $mailer = Net::Peep::Mail->new(); $mailer->smtp_server(@SMTP_RELAYS); $mailer->from("Peep Notification <$USER\@$HOSTNAME>"); $mailer->to($self->_getNotificationRecipients($client)); $mailer->subject("[Peep Notification] $client on $HOSTNAME"); $mailer->body($self->_getBody($client)); if ($mailer->send()) { $self->_setSendTime($client); $self->_garbageCollect($client); return 1; } else { return 0; } } } # end sub _notify sub _getNotifications { # Return only those notifications exceeding the notification # threshhold defined in the Peep configuration file for the # specified client my $self = shift; my $client = shift || confess "client not found"; return () unless $self->_notificationExists($client); my $level = $NOTIFICATION_LEVEL{$client} || confess "Notification level for client [$client] not found."; if ($level eq 'crit') { return grep $_->status() eq 'crit', @{$NOTIFICATIONS->{$client}->{'NOTIFICATIONS'}}; } elsif ($level eq 'warn') { return grep $_->status() =~ /warn|crit/, @{$NOTIFICATIONS->{$client}->{'NOTIFICATIONS'}}; } else { return @{$NOTIFICATIONS->{$client}->{'NOTIFICATIONS'}}; } } # end sub _getNotifications sub _getBody { my $self = shift; my $client = shift; return undef unless $self->_notificationExists($client); my @notifications = $self->_getNotifications($client); my $n_notifications = scalar(@notifications); my $time = scalar(localtime(time())); my $body = <<"eop"; User: $USER Host: $HOSTNAME Client: $client Time: $time Notifications: $n_notifications eop ; my $i = 1; # reverse the order of notifications to get the most recent first for my $notification (reverse @notifications) { my $status = ucfirst($notification->status()); my $message = $notification->message(); my $time = scalar(localtime($notification->datetime())); $body .= <<"eop"; \[Notification $i: $status at $time\] $message eop ; $i++; } return $body; } # end sub _getBody sub store { # store failsafe information for future reference my $self = shift; my $notification = shift; # a Net::Peep::Notification object my $client = $notification->client() || confess "client not found"; push @{$NOTIFICATIONS->{$client}->{'NOTIFICATIONS'}}, $notification; return 1; } # end sub store sub _sendTimeExists { my $self = shift; my $client = shift || confess "client not found"; if (exists $NOTIFICATIONS->{$client} && exists $NOTIFICATIONS->{$client}->{'SEND_TIME'}) { return 1; } else { return 0; } } # end sub _sendTimeExists sub _setSendTime { my $self = shift; my $client = shift || confess "client not found"; $NOTIFICATIONS->{$client}->{'SEND_TIME'} = time(); } # end sub _setSendTime sub _getSendTime { my $self = shift; my $client = shift || confess "client not found"; if (exists $NOTIFICATIONS->{$client}) { if (exists $NOTIFICATIONS->{$client}->{'SEND_TIME'}) { return $NOTIFICATIONS->{$client}->{'SEND_TIME'}; } else { confess "Cannot find SEND_TIME key for client [$client]"; } } else { return undef; } } # end sub _getSendTime sub _garbageCollect { # clear out old notification information my $self = shift; my $client = shift || confess "client not found"; delete $NOTIFICATIONS->{$client}->{NOTIFICATIONS} if exists $NOTIFICATIONS->{$client} && exists $NOTIFICATIONS->{$client}->{NOTIFICATIONS}; $NOTIFICATIONS->{$client}->{NOTIFICATIONS} = []; return 1; } # end sub _garbageCollect sub force { # clear out any unsent notifications whether or not they're ready # to be sent my $self = shift; my $force = 1; my $n; for my $client (keys %$NOTIFICATIONS) { if (exists $NOTIFICATIONS->{$client}->{'NOTIFICATIONS'} && exists $NOTIFICATIONS->{$client}->{'SEND_TIME'}) { my @notifications = @{$NOTIFICATIONS->{$client}->{'NOTIFICATIONS'}}; $n = @notifications; $self->notify($notifications[0],$force) if @notifications; } } return $n; } # end sub force sub flush { # clear out any unsent notifications that are ready to be sent my $notifier = Net::Peep::Notifier->new(); for my $client (keys %$NOTIFICATIONS) { if (exists $NOTIFICATIONS->{$client}->{'NOTIFICATIONS'} && exists $NOTIFICATIONS->{$client}->{'SEND_TIME'}) { my @notifications = @{$NOTIFICATIONS->{$client}->{'NOTIFICATIONS'}}; $notifier->notify($client); } } } # end sub flush 1; __END__