File send_irc_message of Package nagios-eventhandlers-send_mail

#!/usr/bin/perl
#
# Copyright (C) 2012 SUSE Linux Products GmbH
#
# 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 2
# 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, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street,
# Fifth Floor,
# Boston, MA  02110-1301,
# USA.
#

use strict;
use warnings;
use Carp;
use Config::IniFiles;
use English qw( -no_match_vars );
use Getopt::Long;
use Pod::Usage;
use URI::Escape;

our $conf={
    VERSION         => '0.1.3',
    PROGNAME        => 'send_irc_message',
    config          => '/etc/nagios/send_irc_message.cfg',
    debug           => 0,
    logfile         => '/var/log/nagios/send_irc_message.log',
    netcat          => '/usr/bin/netcat',
    printf          => '/usr/bin/printf',
    loglevel 		=> 1,
    servicealert 	=> 0,
    acknowledgement	=> 0,
    version         => 0,
};

our @config_options=qw(
	irc_bot_host
	irc_bot_channel
	irc_bot_port
	nagios_url
	timeout
	logfile	
	loglevel
	debug
);

our @needed=qw(
	irc_bot_host
	irc_bot_channel
    irc_bot_port
	nagios_url
	timeout
	logfile	
);

my $print_help=0;

#######################################################################
## Function Area
#######################################################################
sub logfile {
    my ($action,$config_ref)=@_;
    if (!defined($config_ref->{'loglevel'}) || $config_ref->{'loglevel'} eq ""){
        $config_ref->{'loglevel'}=0;
    }
    if (("$action" eq "open" ) || ("$action" eq "new" )) {
        open (my $fh, ">>$config_ref->{'logfile'}") or croak "Couldn't open ".$config_ref->{'logfile'}." !\n";
        flock($fh,2) or croak "Can't get lock for $config_ref->{'logfile'} !\n";
        return $fh;
    } else {
        close $config_ref->{'logfile_fh'} or croak("Could not close filehandle $config_ref->{'logfile_fh'}\n");
    }
}

sub LOG {
    my ($message,$level,$config_ref)=@_;
    my $time = localtime(time);
    my $fh=$config_ref->{'logfile_fh'};
    if ($level <= $config_ref->{'loglevel'}){
        print $fh "$time [".$config_ref->{'PROGNAME'}."] : $message\n" or croak("Could not write to logfile\n");
    }
    print STDERR "DEBUG: $message\n" if ($config_ref->{'debug'});
}

sub check_ini_section($$$){
    my ($iniref,$name,$needed_ref)=@_;
        foreach my $needed (@$needed_ref){
            if (!defined($iniref->val("$name","$needed"))){
                return "$needed";
            }
        }
    return 0
}

sub cleanup_and_exit($$){
        my ($conf,$exitcode)=@_;
        logfile('close',$conf);
        exit $exitcode;
}

sub sendmsg($$){
	my($conf,$ini)=@_;

	my $timeout=$ini->val('global','timeout');
	my $irchost=$ini->val('global','irc_bot_host');
	my $ircchannel="#".$ini->val('global','irc_bot_channel');
	my $ircport=$ini->val('global','irc_bot_port');
	my $debug=$conf->{'debug'};
	my $message='';
	my $url=$ini->val('global','nagios_url');
	my $host=uri_escape($conf->{'hostname'});

	# Create correct URL
	if ($conf->{'servicealert'}){
		my $service=uri_escape($conf->{'servicename'});
		$url.="?type=2&host=".$host."&service=".$service;
	}
	else {
		$url.="?type=1&host=".$host;
	}

	# Problem acknowledged ?
	if ($conf->{'acknowledgement'}){
		if ($conf->{'servicealert'}){
			$message="$conf->{'notificationtype'} ($conf->{'servicename'} on $conf->{'hostname'}) acknowledged by $conf->{'authorname'}: $conf->{'comment'}";
		}
		else {
			$message="$conf->{'notificationtype'} ($conf->{'hostname'}) acknowledged by $conf->{'authorname'}: $conf->{'comment'}";
		}
	}
	elsif ($conf->{'servicealert'}){
	    # Service Problem
		$message="$conf->{'notificationtype'}: $conf->{'servicename'} on $conf->{'hostname'} - $conf->{'output'} ; See $url";
	}
	else {
        # Host Problem
		$message="$conf->{'notificationtype'}: $conf->{'hostname'} - $conf->{'output'} ; See $url";
	}

	# send out the message
	my $status = system("$conf->{'printf'} \"%b\" \"$ircchannel $message\" | $conf->{'netcat'} -w $timeout $irchost $ircport");
	# log output, if something goes wrong
	if (($status >>=8) != 0){
		LOG("Failed to run $conf->{'netcat'}",1,$conf);	
	}
	else {
		# just log if the user wants it
		LOG("Sent out: $ircchannel $message",4,$conf);
	}
}

sub print_version($){
	my ($conf)=@_;
	print "$conf->{'PROGNAME'} v$conf->{'VERSION'}\n";
	print "This script come with ABSOLUTELY NO WARRANTY. You may redistribute\n";
	print "copies of the plugins under the terms of the GNU General Public License.\n";
	print "For more information about these matters, see the file named COPYING.\n";
}

#######################################################################
## Main Area
#######################################################################
Getopt::Long::Configure('bundling');
GetOptions( "h|help"                => \$print_help,
            "c|config=s"            => \$conf->{'config'},
            "d|debug"               => \$conf->{'debug'},
            "v|version"             => \$conf->{'version'},
            "n|notificationtype=s"  => \$conf->{'notificationtype'},  # $NOTIFICATIONTYPE$
            "H|hostname=s"          => \$conf->{'hostname'},          # $HOSTNAME$
            "S|servicename=s"       => \$conf->{'servicename'},       # $SERVICEDESC$
            "a|authorname=s"        => \$conf->{'authorname'},        # $SERVICEACKAUTHORNAME$, $HOSTACKAUTHORNAME$
            "c|comment=s"           => \$conf->{'comment'},           # $SERVICEACKCOMMENT$, $HOSTACKCOMMENT$
            "s|state=s"             => \$conf->{'state'},             # $SERVICESTATE$, $HOSTSTATE$
            "o|output=s"            => \$conf->{'output'}             # $SERVICEOUTPUT$, $HOSTOUTPUT$
) or pod2usage(2);

pod2usage(  -exitstatus => 0,
            -verbose => 1,  # 2 to print full pod
         ) if $print_help;

if ($conf->{'version'}){
	print_version($conf);
	exit 0;
}

if ( ! -f "$conf->{'config'}"){
	print STDERR "$conf->{'config'} not found or not readable\n";
	exit 1;
}

my $ini = new Config::IniFiles( -file => "$conf->{'config'}",
                                -default => "global",
                                -allowcontinue => 1);

if( ! $ini ){
        croak("Couldn't open $conf->{'config'} : $!\n");
}

$conf->{'logfile'}=$ini->val('global','logfile') if $ini->val('global','logfile');
$conf->{'loglevel'}=$ini->val('global','loglevel') if $ini->val('global','loglevel');

my $logfile_ref=logfile('open',$conf);
$conf->{'logfile_fh'}=$logfile_ref;

foreach my $section ( $ini->Sections() ){
	my $res=check_ini_section($ini,$section,\@needed);
	if ($res){
		LOG("Needed element $res not found in $section from $conf->{'config'} - skipping",2,$conf);
		next;
	}
}

# first check, if we have the absolute minimum to send out IRC notifications
if (not defined $conf->{'hostname'} or $conf->{'hostname'} eq ''){
	LOG("Option -H (--hostname) not defined",1,$conf);
	$conf->{'hostname'}='UNDEFINED';
}
if (not defined $conf->{'notificationtype'} or $conf->{'notificationtype'} eq ''){
	LOG("Option -n (--notificationtype) not defined",1,$conf);
	$conf->{'notificationtype'}='UNDEFINED';
}
if (not defined $ini->val('global','irc_bot_channel') or $ini->val('global','irc_bot_channel') eq ''){
	LOG("Config option irc_bot_channel not defined in config - this will not produce any output",1,$conf);
}
if (not defined $conf->{'state'} or $conf->{'state'} eq ''){
	LOG("Option -s (--state) not defined",1,$conf);
	$conf->{'state'}='UNDEFINED';
}
if (not defined $conf->{'output'} or $conf->{'output'} eq ''){
	LOG("Option -o (--output) not defined",1,$conf);
	$conf->{'output'}='UNDEFINED';
}
if (defined $conf->{'servicename'} and $conf->{'servicename'} ne ''){
	$conf->{'servicealert'}=1;
}
if (defined $conf->{'authorname'} and $conf->{'authorname'} ne ''){
	$conf->{'acknowledgement'}=1;
}
if ($conf->{'notificationtype'} eq 'ACKNOWLEDGEMENT'){
	$conf->{'acknowledgement'}=1;
}


if ($conf->{'debug'}){
    use Data::Dumper;
    print STDERR "Config:\n".Data::Dumper->Dump([$conf])."\n";
    print STDERR "Ini:\n".Data::Dumper->Dump([$ini])."\n";  
}

sendmsg($conf,$ini);

cleanup_and_exit($conf,0);

__END__

=head1 Send Nagios IRC notifications

Commandline tool for sending Nagios notifications via IRC Bot.

=head1 SYNOPSIS

./send_irc_message <OPTIONS>

Example of a service problem/acknowledgement:

 ./send_irc_message \
 --config "/etc/nagios/send_irc_message.cfg" \
 --notificationtype "$NOTIFICATIONTYPE$" \
 --state "$SERVICESTATE$" \
 --hostname "$HOSTNAME$" \
 --output "$SERVICEOUTPUT$" \
 --servicename "$SERVICEDESC$" \
 --authorname "$SERVICEACKAUTHORNAME$" \
 --comment "$SERVICEACKCOMMENT$"


Example of a host problem/acknowledgement:

 ./send_irc_message \
 --config "/etc/nagios/send_irc_message.cfg" \
 --notificationtype "$NOTIFICATIONTYPE$" \
 --state "$HOSTSTATE$" \
 --hostname "$HOSTNAME$" \
 --output "$HOSTOUTPUT$" \
 --authorname "$HOSTACKAUTHORNAME$" \
 --comment "$HOSTACKCOMMENT$"

Options:

    -c <file>              | --config <file>
    -H <host>              | --hostname <host>
    -S <service>           | --servicename <host>
    -n <notificationtype>  | --notificationtype <notificationtype>
    -a <authorname>        | --authorname <authorname>
    -c <comment>           | --comment <comment>
    -s <state>             | --state <state>
    -o <output>            | --output <output>

    -h                     | --help
    -d                     | --debug

=head1 OPTIONS

=over 8

=item B<--config> F<file>

Use configfile F<file> instead of default F</etc/nagios/send_irc_message.cfg>. This config file is a standard ini-file and 
can contain the following values:

 [global]
 # please fill in at least these settings:
 irc_bot_host=localhost
 irc_bot_channel=nagios-admin  # please do NOT use a '#' here, the script will add this for you
 irc_bot_port=5050
 nagios_url=https://$nagioshost/nagios/cgi-bin/extinfo.cgi
 timeout=1
 logfile=/var/log/nagios/send_irc_message.log
 # those settings are optional:
 loglevel=2
 debug=0

=item B<--hostname> F<HOST>

Same as $HOSTNAME$ in Nagios. 
(Example: "myhost.example.com")

=item B<--servicename> F<SERVICEDESC>

Same as $SERVICEDESC$ in Nagios. 
(Example: "MySQL Service")

=item B<--notificationtype> -F<NOTIFICATIONTYPE>

Same as $NOTIFICATIONTYPE$ in Nagios. 
(Example: "PROBLEM")

=item B<--authorname> F<author>

Same as $SERVICEACKAUTHORNAME$ resp. $HOSTACKAUTHORNAME$ in Nagios. 
(Example: "Nagios Admin")

=item B<--comment> F<comment>

Same as $SERVICEACKCOMMENT$ resp. $HOSTACKCOMMENT$ in Nagios. 
(Example: "too late to fix")

=item B<--state> F<state>

Same as $SERVICESTATE$ resp. $HOSTSTATE$ in Nagios. 
(Example: "CRITICAL")

=item B<--output> F<output>

Same as $SERVICEOUTPUT$ resp. $HOSTOUTPUT$ in Nagios. 
(Example: "Cant connect to local MySQL server")

=item B<nagios_url> L<https://$nagioshost/nagios/cgi-bin/extinfo.cgi>

URL to extinfo.cgi - the rest will be filled automatically with the given values above. 
(Example: "https://nagios.example.com/nagios/cgi-bin/extinfo.cgi")

=back

=head1 DESCRIPTION

Instead of using the standard printf commandline given by Nagios, you can use this script to generate
notification IRC messages via an IRC-Bot together with Nagios.

We recommend the use of Supybot + supybot-notify plugin. The Bot can run on any other host that is 
reachable by your Nagios server and has the desired port open for the communication.

This script will take care of unset variables and adds the ability to format the output in your way.

=head1 COPYRIGHT

=over 4

=item Copyright 2012 Lars Vogdt <lrupp@suse.de>. 

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

=back

=cut
openSUSE Build Service is sponsored by