#!/usr/bin/perl -w
#
# ########################### nagios_send_host_mail.pl ################ #
# Date : July 16, 2012 #
# Purpose : Script to send out Nagios e-mails.\n"; #
# Author : Frank Migge (support at frank4dd dot com) #
# Help : http://nagios.frank4dd.com/howto #
# Licence : GPL - http://www.fsf.org/licenses/gpl.txt #
# Written for and verified with Nagios version 3.4.1 #
# Help : ./nagios_send_host_mail.pl -h #
# Depends : perl-Mail-Sendmail (Mail::Sendmail) #
# perl-MIME-tools (MIME::Base64) #
# rrdtool-devel #
# libnetpbm (conversion png-to-jpg) #
# netpbm (see above) #
# ##################################################################### #
use Getopt::Long;
use Mail::Sendmail;
use Digest::MD5 qw(md5_hex);
use MIME::Base64;
use File::Temp;
use RRDs;
use strict;
use warnings;
use vars qw( $logo_id $graph_id $tmpfile $land $tbl $var
%param_vars $elapse $tstamp $tstart $img_get);
# The version of this script
my $Version ='1.7.3';
# the sender e-mail address to be seen by recipients
my $mail_sender = "Nagios Monitoring <nagios\@frank4dd.com>";
# The Nagios CGI URL for integrated links
my $nagios_cgiurl = "http://nagios.frank4dd.com/nagios/cgi-bin";
# Here we define a simple HTML stylesheet to be used in the HTML header.
my $html_style = "body {text-align: center; font-family: Verdana, sans-serif; font-size: 10pt;}\n"
. "img.logo {float: left; margin: 10px 10px 10px; vertical-align: middle}\n"
. "span {font-family: Verdana, sans-serif; font-size: 12pt;}\n"
. "table {text-align:center; margin-left: auto; margin-right: auto;}\n"
. "th {white-space: nowrap;}\n"
. "th.even {background-color: #D9D9D9;}\n"
. "td.even {background-color: #F2F2F2;}\n"
. "th.odd {background-color: #F2F2F2;}\n"
. "td.odd {background-color: #FFFFFF;}\n"
. "th,td {font-family: Verdana, sans-serif; font-size: 10pt; text-align:left;}\n"
. "th.customer {width: 600px; background-color: #004488; color: #ffffff;}";
my $table_size = "600px";
my $header_size = "180px";
my $data_size = "420px";
my $debugtables = "<br>\n";
# ########################################################################
# For tests using the -t/--test option, if we want to see Nagiosgraph
# graphs we need to set a valid host name and service name below.
# ########################################################################
my $test_host = "susie114"; # existing host in Nagios
# ########################################################################
# Here we set the information where to pick up the RRD data files for the
# optional graph image generation, plus the graph size width x height px
# ########################################################################
my $ngraph_cgiurl = "http://nagios.frank4dd.com/nagios/cgi-bin/show.cgi";
my $rrd_basedir = "/srv/app/nagiosgraph/rrd";
my $graph_img_size = "521x60";
my $graph_bgcolor = "#F2F2F2";
my $graph_border = "#999999";
# ########################################################################
# SMTP related data: If the commandline argument -H/--smtphost was not
# given, we use the provided value in $o_smtphost below as the default.
# If the mailserver requires auth, an example is further down the code.
# ########################################################################
my $o_smtphost = "192.168.1.64";
my $domain = "\@yourdomain"; # only for -g group
my @listaddress = ();
# ########################################################################
# This is the logo image file, the path must point to a valid JPG, GIF or
# PNG file, i.e. the nagios logo. Best size is rectangular up to 160x80px.
# example: [nagioshome]/share/images/NagiosEnterprises-whitebg-112x46.png
# ########################################################################
my $logofile = "/srv/www/std-root/nagios.frank4dd.com/images/nagios-logo.gif";
# ########################################################################
# Because our mail system being Lotus Notes, which is not supporting PNG
# images, we must convert them from PNG to JPG before we can continue.
# Set $jpg_workaround = true if your mail client has the same trouble.
# ########################################################################
my $jpg_workaround = undef;
# ########################################################################
# Here I define the HTML color values for each Nagios notification type.
# There is one extra called TEST for sending a test e-mail from the cmdline
# outside of Nagios. The color values are used for highlighting the
# background of the notification type cell.
# ########################################################################
my %NOTIFICATIONCOLOR=('PROBLEM'=>'#FF8080','RECOVERY'=>'#80FF80','ACKNOWLEDGEMENT'=>'FFFF80',
'DOWNTIMESTART'=>'80FFFF','DOWNTIMEEND'=>'80FF80','DOWNTIMECANCELLED'=>'FFFF80',
'FLAPPINGSTART'=>'#FF8080','FLAPPINGSTOP'=>'#80FF80',' FLAPPINGDISABLED'=>'FFFF80',
'TEST'=>'80FFFF');
# ########################################################################
# language translated message text: $language{$land}{'A'} (=Customer)
# You can simply add here your translation...
# ########################################################################
my %language = ('en' => { 'A' => 'Customer',
'B' => 'Notification Type',
'C' => 'Host Status',
'D' => 'Hostname',
'E' => 'Hostalias',
'F' => 'IP Address',
'G' => 'Hostgroup',
'H' => 'Event Time',
'I' => 'Host Output',
'J' => 'Author',
'K' => 'Comment',
'L' => 'Nagios Monitoring System Notification',
'M' => 'Generated by Nagios, the OpenSource monitoring solution' },
'fr' => { 'A' => 'Utilisateur',
'B' => 'Type de notification',
'C' => 'Statut d\'hôte',
'D' => 'Nom d\'hôte',
'E' => 'Alias d\'hôte',
'F' => 'Adresse IP',
'G' => 'Groupe d\'hôte',
'H' => 'Heure de la notification',
'I' => 'Données',
'J' => 'Auteur',
'K' => 'Commentaire',
'L' => 'Notification de la surveillance Nagios',
'M' => 'Généré par Nagios, le système de surveillance OpenSource' },
'de' => { 'A' => 'Anwender',
'B' => 'Nachrichtentyp',
'C' => 'Systemzustand',
'D' => 'Systemname',
'E' => 'Systemalias',
'F' => 'System IP Adresse',
'G' => 'Systemgruppe',
'H' => 'Meldungsdatum',
'I' => 'Systemnachricht',
'J' => 'Author',
'K' => 'Kommentar',
'L' => 'Nagios Überwachungssytem Meldung',
'M' => 'Erstellt mit Nagios, dem OpenSource Überwachungssytem' },
'jp' => { 'A' => '顧客名',
'B' => '通知の種類',
'C' => 'ホストの状態',
'D' => 'ホスト名',
'E' => 'ホストの別名',
'F' => 'IPアドレス',
'G' => 'ホストグループ',
'H' => 'イベントの日付と時刻',
'I' => 'ホストデータ出力',
'J' => '投稿者',
'K' => 'コメント',
'L' => 'Nagios 監視システムの通知',
'M' => 'このメッセージはオープンソースの監視システムNagiosで生成されています。' });
####### Global Variables - No changes necessary below this line ##########
# Nagios notification type, i.e. PROBLEM
my $o_notificationtype = $ENV{NAGIOS_NOTIFICATIONTYPE};
# Nagios notification author (if avail.)
my $o_notificationauth = $ENV{NAGIOS_NOTIFICATIONAUTHOR};
# Nagios notification comment (if avail.)
my $o_notificationcmt = $ENV{NAGIOS_NOTIFICATIONCOMMENT};
# Nagios monitored host name
my $o_hostname = $ENV{NAGIOS_HOSTNAME};
# Nagios monitored host alias
my $o_hostalias = $ENV{NAGIOS_HOSTALIAS};
# Nagios host group the host belongs to
my $o_hostgroup = $ENV{NAGIOS_HOSTGROUPNAME};
# Nagios monitored host IP address
my $o_hostaddress = $ENV{NAGIOS_HOSTADDRESS};
# Nagios monitored host state, i.e. DOWN
my $o_hoststate = $ENV{NAGIOS_HOSTSTATE};
# Nagios monitored host check output data
my $o_hostoutput = $ENV{NAGIOS_HOSTOUTPUT};
# Nagios date when the event was recorded
my $o_datetime = $ENV{NAGIOS_LONGDATETIME};
# The recipients defined in $CONTACTEMAIL$
my $o_to_recipients = $ENV{NAGIOS_CONTACTEMAIL};
# Modified by Robert Becht for using $CONTACTGROUPEMEMBERS$ in nagios.conf
my $recipient_group = $ENV{NAGIOS_CONTACTGROUPMEMBERS};
# The next variables are provided through args
my $o_to_group = undef; # this flag is only set with the -g option
my $o_cc_recipients = undef; # The recipients defined in $CONTACTADDRESS1$
my $o_bcc_recipients = undef; # The recipients defined in $CONTACTADDRESS2$
my $o_format = "text";# The e-mail output format (default: text)
my $o_addurl = undef; # flag to add Nagios GUI URLs to HTML e-mails
my $o_language = undef; # The e-mail output language
my $o_lang_def = "en"; # The e-mail output language default
my $o_customer = undef; # Company name and contract number for service providers
my $o_help = undef; # We want help
my $o_verb = undef; # verbose mode
my $o_version = undef; # print version
my $o_test = undef; # generate a test message
# These variables are used in various subroutines
my $text_msg = undef; # the plaintext notification
my $html_msg = undef; # the HTML-formatted notification
my $graphfile = undef; # if we generate graphs, the tmp file location
my $logo_img = undef; # base64-encoded logo
my $logo_type = undef; # logo image file format (jpg, gif, or png)
my $graph_img = undef; # base64-encoded graph
my $graph_type = undef; # graph image file format (jpg, gif, or png)
my $boundary = undef; # unique string for multi-part emails
my %mail;
# $empty_img is a base64-encoded, white 1x1 pixel gif image, we
# use it if the logo or the Nagiosgraph data cannot be found.
my $empty_img = "R0lGODlhAQABAJEAAAAAAP///////wAAACH5BAEAAAIALAAAAAABAAEAAAICTAEAOw==";
# ########################################################################
# subroutine defintions below
# ########################################################################
# ########################################################################
# p_version returns the program version
# ########################################################################
sub p_version { print "nagios_send_host_mail.pl version : $Version\n"; }
# ########################################################################
# print_usage returns the program usage
# ########################################################################
sub print_usage {
print "Usage: $0 [-v] [-V] [-h] [-t] [-H <SMTP host>] [-p <customername>]
[-r <to_recipients>] or -g <to_group>] [-c <cc_recipients>] [-b <bcc_recipients>]
[-f <text|html|multi|graph>] [-u] [-l <en|jp|fr|de>(or other languages if added]\n";
}
# ########################################################################
# help returns the program help message
# ########################################################################
sub help {
print "\nNagios e-mail notification script for host events, version ",$Version,"\n";
print "This version was developed for inclusion of Nagiosgraph performance graphs.\n";
print "GPL licence, (c)2012 Frank Migge\n\n";
print_usage();
print <<EOT;
This script takes over Nagios e-mail notifications by receiving the Nagios state
information, formatting the e-mail and sending it out through an SMTP gateway.
-v, --verbose
print extra debugging information
-V, --version
prints version number
-h, --help
print this help message
-t, --test
generates a test message together with -r, --to-recipients
-H, --smtphost=HOST
name or IP address of SMTP gateway
-p, --customer="customer name and contract #"
optionally, add the customer name and contract for service providers
-r, --to-recipients
override the Nagios-provided \$CONTACTEMAIL\$ list of to: recipients
-g, --to-group-recipients in \$CONTACTGROUPMEMBERS\$
instead of -r, use the list of contactgroup members and complete the mail
address with the hard defined \$domain in this script. This is only possible
when the contact name "abcd" works under the address "abcd\@domain".
-c, --cc-recipients
the Nagios-provided \$CONTACTADDRESS1\$ list of cc: recipients
-b, --bcc-recipients
the Nagios-provided \$CONTACTADDRESS2\$ list of bcc: recipients
-f, --format='text|html|multi|graph'
the email format to generate: plain ASCII text, HTML, multipart S/MIME with
a logo, or multipart S/MIME - adding the Nagiosgraph performance graph image
-u, --addurl
this adds URL's to the Nagios web GUI for check status, host and hostgroup
views into the html mail, requires -f html, multi or graph
-l, --language='en|jp|fr|de|(or what you defined in this script)'
the prefered e-mail language. The content-type header is hard-coded to UTF-8.
Check if your recipients require a different characterset encoding.
Extra: Additional debug output can be generated. Within Nagios, select a host
and choose "Send custom host notification". Entering text, including the
keyword "email-debug" into the "Comment" field will add additional tables
containing a list of values for important Nagios and script variables.
EOT
}
# ########################################################################
# verb creates verbose output
# ########################################################################
sub verb { my $t=shift; print $t,"\n" if defined($o_verb) ; }
# ########################################################################
# unique content ID are needed for mulitpart messages with inline logos
# ########################################################################
sub create_content_id {
my $unique_string = rand(100);
$unique_string = $unique_string . substr(md5_hex(time()),0,23);
$unique_string =~ s/(.{5})/$1\./g;
my $content_id = qq(part.${unique_string}\@) . "MAIL";
$unique_string = undef;
return $content_id;
}
# ########################################################################
# create_boundary creates the S/MIME multipart boundary strings
# ########################################################################
sub create_boundary {
my $unique_string = substr(md5_hex(time()),0,24);
$boundary = '======' . $unique_string ;
$unique_string = undef;
}
sub unknown_arg {
print_usage();
exit -1;
}
# ########################################################################
# create_address adds the domain to the groupmembers list (Robert Becht)
# ########################################################################
sub create_address {
chomp($recipient_group);
my @mlist = split(",",$recipient_group);
foreach (@mlist) {
my $maddress = "$_"."$domain";
push(@listaddress,$maddress);
}
$recipient_group = join(",",@listaddress);
return ($recipient_group);
}
# ########################################################################
# check_options checks and processes the commandline options given
# ########################################################################
sub check_options {
Getopt::Long::Configure ("bundling");
GetOptions(
'v' => \$o_verb, 'verbose' => \$o_verb,
'V' => \$o_version, 'version' => \$o_version,
'h' => \$o_help, 'help' => \$o_help,
't' => \$o_test, 'test' => \$o_test,
'H:s' => \$o_smtphost, 'smtphost:s' => \$o_smtphost,
'p:s' => \$o_customer, 'customer:s' => \$o_customer,
'r:s' => \$o_to_recipients, 'to-recipients:s' => \$o_to_recipients,
'g:s' => \$o_to_group, 'to-group-recipients' => \$o_to_group,
'c:s' => \$o_cc_recipients, 'cc-recipients:s' => \$o_cc_recipients,
'b:i' => \$o_bcc_recipients, 'bcc-recipients:s' => \$o_bcc_recipients,
'f:s' => \$o_format, 'format:s' => \$o_format,
'u' => \$o_addurl, 'addurl' => \$o_addurl,
'l:s' => \$o_language, 'language:s' => \$o_language,
) or unknown_arg();
# Basic checks
if (defined ($o_help) ) { help(); exit 0};
if (defined($o_version)) { p_version(); exit 0};
if ( ! defined($o_to_recipients) ) # no recipients provided
{ print "Error: no recipients have been provided\n"; print_usage(); exit -1}
else {
if (! defined($o_to_group)) {
%mail = ( To => $o_to_recipients,
From => $mail_sender,
Sender => $mail_sender ); }
else {
&create_address;
%mail = ( To => $recipient_group,
From => $mail_sender,
Sender => $mail_sender ); }
}
if ( $o_format ne "text" && $o_format ne "html"
&& $o_format ne "multi" && $o_format ne "graph") # wrong mail format
{ print "Error: wrong e-mail format.\n"; print_usage(); exit -1}
if (defined($o_addurl) && $o_format eq "text")
{ print "Error: cannot add URL's to text.\n"; print_usage(); exit -1}
if (defined($o_test)) { create_test_data(); };
# Modified by Robert Becht to support additional languages
# if no language has been requested, try to determine default from OS
if (! defined($o_language)) {
# if environment $LANG is set, try to extract the first two country chars, i.e. "en|de|fr"
if ($ENV{LANG} eq "C" || $ENV{LANG} eq "POSIX") { $land = "en"; }
else { ($land, my $rem) = split('_',$ENV{LANG}, 2); }
} else { $land = $o_language; }
# Last resort: Set "English" if the requested language is not supported by our script
if (! $language{$land}{'A'}) { $land = $o_lang_def; }
}
# ########################################################################
# if -t or --test, we need to create sample test data to for sending out.
# Most data is hardcoded. For graph generation, host and service names
# must be valid so the script can pick up data from Nagiosgraph.
# ########################################################################
sub create_test_data {
if (! defined($o_customer)){ $o_customer = "ACME Corporation";}
if (! defined($o_notificationtype)){ $o_notificationtype = "TEST";}
if (! defined($o_hoststate)){ $o_hoststate = "UNKNOWN";}
if (! defined($o_hostname)){ $o_hostname = $test_host;}
if (! defined($o_hostalias)){ $o_hostalias = "Test host alias (placeholder)";}
if (! defined($o_hostaddress)){ $o_hostaddress = "192.168.1.1";}
if (! defined($o_hostgroup)){ $o_hostgroup = "Linux Servers";}
if (! defined($o_datetime)){ $o_datetime = `date`;}
if (! defined($o_hostoutput)){ $o_hostoutput = "Test output for this host";}
if (! defined($o_notificationauth)){ $o_notificationauth = "John Doe";}
# Setting the keyword "email-debug" in the notification comment below triggers the creation of debug tables
if (! defined($o_notificationcmt)){ $o_notificationcmt = "Host notification test message including email-debug";}
}
# ########################################################################
# Create a plaintext message -> $text_msg
# ########################################################################
sub create_message_text {
$text_msg = $language{$land}{'L'}."\n"
. "=====================================\n\n";
# if customer name was given for service providers, display it here
if ( defined($o_customer)) {
$text_msg .= $language{$land}{'A'} . ": $o_customer\n";
}
$text_msg = $text_msg
. $language{$land}{'B'} . ": $o_notificationtype\n"
. $language{$land}{'C'} . ": $o_hoststate\n"
. $language{$land}{'D'} . ": $o_hostname\n"
. $language{$land}{'E'} . ": $o_hostalias\n"
. $language{$land}{'F'} . ": $o_hostaddress\n"
. $language{$land}{'G'} . ": $o_hostgroup\n"
. $language{$land}{'H'} . ": $o_datetime\n"
. $language{$land}{'I'} . ": $o_hostoutput\n\n";
# if author and comment data has been passed from Nagios
# and these variables have content, then we add two more columns
if ( ( defined($o_notificationauth) && defined($o_notificationcmt) ) &&
( ($o_notificationauth ne "") && ($o_notificationcmt ne "") ) ) {
$text_msg .= $language{$land}{'J'} . ": $o_notificationauth\n"
. $language{$land}{'K'} . ": $o_notificationcmt\n\n";
}
$text_msg .= "-------------------------------------\n"
. $language{$land}{'M'} . "\n";
}
# ########################################################################
# Create a HTML message -> $html_msg, per flags include URL's and IMG's
# ########################################################################
sub create_message_html {
# Start HTML message definition
$html_msg = "<html><head><style type=\"text/css\">$html_style</style></head><body>\n"
. "<table width=$table_size><tr>\n";
if ($o_format eq "multi" || $o_format eq "graph") {
$logo_id = create_content_id();
$html_msg .= "<td><img class=\"logo\" src=\"cid:$logo_id\"></td>"
. "<td><span>$language{$land}{'L'}</span></td></tr><tr>\n";
} else {
$html_msg .= "<th colspan=2><span>$language{$land}{'L'}</span></th></tr><tr>\n"; }
if ( defined($o_customer)) {
$html_msg .= "<th colspan=2 class=customer>$o_customer</th></tr><tr>\n"; }
$html_msg = $html_msg
. "<th width=$header_size class=even>$language{$land}{'B'}:</th>\n"
. "<td bgcolor=$NOTIFICATIONCOLOR{$o_notificationtype}>\n"
. "$o_notificationtype</td></tr>\n"
. "<tr><th class=odd>$language{$land}{'C'}:</th><td>$o_hoststate</td></tr>\n"
. "<tr><th class=even>$language{$land}{'D'}:</th><td class=even>\n";
if (defined($o_addurl)) {
$html_msg .= "<a href=\"$nagios_cgiurl/status.cgi?host=" . urlencode($o_hostname) ."&style=detail\">$o_hostname</a>";
} else { $html_msg .= $o_hostname; }
$html_msg = $html_msg . "</td></tr>\n"
. "<tr><th class=odd>$language{$land}{'E'}:</th><td>$o_hostalias</td></tr>\n"
. "<tr><th class=even>$language{$land}{'F'}:</th><td class=even>$o_hostaddress</td></tr>\n"
. "<tr><th class=odd>$language{$land}{'G'}:</th><td>\n";
if (defined($o_addurl)) {
$html_msg = $html_msg
. "<a href=\"$nagios_cgiurl/status.cgi?hostgroup=" . urlencode($o_hostgroup) ."&style=overview\">$o_hostgroup</a>";
} else { $html_msg .= $o_hostgroup; }
$html_msg = $html_msg . "</td></tr>\n"
. "<tr><th class=even>$language{$land}{'H'}:</th><td class=even>$o_datetime</td></tr>\n"
. "<tr><th class=odd>$language{$land}{'I'}:</th><td>\n";
if (defined($o_addurl)) {
$html_msg .= "<a href=\"$nagios_cgiurl/status.cgi?type=1&host=" . urlencode($o_hostname) . "\">$o_hostoutput</a>\n";
# If the graph image wasn't empty, We add an additional link for Nagiosgraph
if ($o_format eq "graph" && $graph_type ne "gif") {
$html_msg .= ", see also <a href=\"$ngraph_cgiurl?host=" . urlencode($o_hostname) ."&service=check-host-alive&geom=". $graph_img_size ."\">Nagiosgraph</a>\n"; }
} else { $html_msg = $html_msg . $o_hostoutput; }
$html_msg = $html_msg . "</td></tr>\n";
# If the author and comment data has been passed from Nagios
# and these variables have content, then we add two more columns
if ( ( defined($o_notificationauth) && defined($o_notificationcmt) ) &&
( ($o_notificationauth ne "") && ($o_notificationcmt ne "") ) ) {
$html_msg .= "<tr><th class=even>$language{$land}{'J'}:</th>\n"
. "<td class=even>$o_notificationauth</td></tr>\n"
. "<tr><th class=odd>$language{$land}{'K'}:</th>\n"
. "<td>$o_notificationcmt</td></tr>\n";
}
$html_msg .= "</table><br>\n";
# if we got the graph format and a image has been generated, we add it here
if (defined($graph_img) && $o_format eq "graph") {
$graph_id = create_content_id();
$html_msg .= "<img src=\"cid:$graph_id\">\n";
}
# add the Nagios footer tag line here
$html_msg .= "<br><hr>\n$language{$land}{'M'}\n<hr>\n";
# add the extra debugtables if verbose output had been requested,
# or if the notification command contains the keyword "email-debug"
if (defined($o_notificationcmt) && ($o_notificationcmt =~ m/email-debug/i)
|| defined($o_verb)) {
&create_debugtable;
$html_msg .= $debugtables;
}
# End HTML message definition
$html_msg .= "</body></html>\n";
}
# #######################################################################
# urlencode() URL encode a string
# #######################################################################
sub urlencode {
my $urldata = $_[0];
my $MetaChars = quotemeta( '-;,/?\|=+)(*&^%$#@!~`:');
$urldata =~ s/([$MetaChars\"\'\x80-\xFF])/"%" . uc(sprintf("%2.2x", ord($1)))/eg;
$urldata =~ s/ /\+/g;
return $urldata;
}
# ########################################################################
# b64encode_image(filename) converts a existing binary source image file
# into a base64-image string.
# ########################################################################
sub b64encode_img {
my($inputfile) = @_;
open (IMG, $inputfile) or verb("b64encode_img: Cannot read source image file: $inputfile - $!");
binmode IMG; undef $/;
my $b64encoded_img = encode_base64(<IMG>);
close IMG;
verb("b64encode_img: completed conversion of source image file: $inputfile - $!");
return $b64encoded_img;
}
# #######################################################################
# hashcolor() Choose a color for the Nagiosgraph RRD service
# #######################################################################
sub hashcolor {
my $c=0;
map{$c=(51*$c+ord)%(216)}split//,"$_[0]x";
my $i = 0;
my $n = 0;
my $m = 0;
my @h=(51*int $c/36,51*int $c/6%6,51*($c%6));
for$i(0..2){$m=$i if$h[$i]<$h[$m];$n=$i if$h[$i]>$h[$n]}
$h[$m]=102if$h[$m]>102;$h[$n]=153if$h[$n]<153;
$c=sprintf"%06X",$h[2]+$h[1]*256+$h[0]*16**4;
return $c;
}
# #######################################################################
# dbfilelist() Get list of matching Nagiosgraph RRD files
# #######################################################################
sub dbfilelist {
my($host,$service, $rrddir) = @_;
my $hs;
# New style, files inside a <hostname> directory
$rrddir .= "/" . $host;
$hs = urlencode "$service" . "___";
verb("sub dbfilelist: Checking files inside directory: ".$rrddir."/".$hs);
my @rrd;
opendir DH, $rrddir;
@rrd = grep s/^${hs}(.+)\.rrd$/$1/, readdir DH;
closedir DH;
verb("sub dbfilelist: We found number of files: ".@rrd);
return @rrd;
}
# #######################################################################
# graphinfo() Find graphs and values in Nagiosgraph
# #######################################################################
sub graphinfo {
my($host,$service,$rrddir) = @_;
my(@rrd,$ds,$f,$dsout,@values,$hs,%H,%R);
$hs = $host . "/";
$hs .= urlencode "$service" . "___";
# Determine which files to read lines from
@rrd = map {{ file=>$_ }}
map { "${hs}${_}.rrd" }
dbfilelist($host,$service, $rrddir);
# we stop processing here if we could not find a file
if (@rrd < 1) {
verb("sub graphinfo: Could not find any graph file.");
return undef;
} else {
verb("sub graphinfo: Listing $hs db files in $rrddir: "
. join ', ', map { $_->{file} } @rrd);
}
for $f ( @rrd ) {
unless ( $f->{line} ) {
$ds = RRDs::info "$rrddir/$f->{file}";
verb("sub graphinfo: RRDs::info ERR " . RRDs::error) if RRDs::error;
map { $f->{line}{$_} = 1}
grep {!$H{$_}++}
map { /ds\[(.*)\]/; $1 }
grep /ds\[(.*)\]/,
keys %$ds;
}
verb("DS $f->{file} lines: " . join ', ', keys %{ $f->{line} } );
}
return \@rrd;
}
# #######################################################################
# rrdline() Generate the Nagiosgraph RRD parameters to produce a graph
# #######################################################################
sub rrdline {
my($host,$service,$geom,$G,$rrddir,$tmpfile) = @_;
my($g,$f,$v,$c,@ds);
my $directory = $rrddir;
@ds = ($tmpfile, '-a', 'PNG', '-t', $service);
push @ds, "--color=BACK$graph_bgcolor",
"--color=SHADEA$graph_border",
"--color=SHADEB$graph_border";
# Identify where to pull data from and what to call it
for $g ( @$G ) {
$f = $g->{file};
verb("file=$f");
# Compute the longest label length
my $longest = (sort map(length,keys(%{ $g->{line} })))[-1];
for $v ( sort keys %{ $g->{line} } ) {
$c = hashcolor($v);
verb("sub rrdline: file=$f line=$v color=$c");
my $sv = "$v";
my $label = sprintf("%-${longest}s", $sv);
push @ds , "DEF:$sv=$directory/$f:$v:AVERAGE"
, "LINE2:${sv}#$c:$label";
my $format = '%6.2lf%s';
# Graph labels
push @ds, "GPRINT:$sv:MAX:Max\\: $format"
, "GPRINT:$sv:AVERAGE:Avg\\: $format"
, "GPRINT:$sv:MIN:Min\\: $format"
, "GPRINT:$sv:LAST:Cur\\: ${format}\\n";
}
}
# Dimensions of graph if geom is specified
if ( $geom ) {
my($w,$h) = split 'x', $geom;
push @ds, '-w', $w, '-h', $h;
}
return @ds;
}
# #######################################################################
# create_graph_img() tries to create a base64-encoded performance graph
# image. It takes the hostname and servicename and tries to find a
# matching RRD file according to the Nagiosgraphs layout. If there is one,
# queries the RRD information and graphs the last 24 hours similar to
# Nagiosgraph.
# #######################################################################
sub create_graph_image {
use FileHandle;
my $G = undef;
# Figure out the correct RRD db files and their line labels
$G = graphinfo($o_hostname,"check-host-alive",$rrd_basedir);
# if we could not find RRD data, we return the empty $graph_img
if(! defined($G)) {
verb("create_graph_image: Cannot generate the Nagiosgraph image file.");
# In this case, we use the 1x1px empty image and return
$graph_type = "gif";
$graph_img = $empty_img;
verb("create_graph_image: Returning empty image file, format: ".$graph_type."\n");
return $graph_img;
}
# generate temporary graph file
my $fhandle = File::Temp->new(UNLINK =>1) or verb("import_pnp_graph: Cannot create temporary image file.");
$fhandle->autoflush(1);
$tmpfile = $fhandle->filename;
my @ds = rrdline($o_hostname,"check-host-alive",$graph_img_size,$G,$rrd_basedir,$tmpfile);
verb("sub create_graph_image: RRDs::graph ". join ' ', @ds);
RRDs::graph(@ds);
verb("sub create_graph_image: RRDs::graph ERR " . RRDs::error) if RRDs::error;
# Because our mail system being Lotus Notes, which is not supporting PNG
# images, we must convert them from PNG to JPG before we can continue.
# Set $jpg_workaround = true if your mail client has the same trouble.
if (defined($jpg_workaround)) {
my $tmpfile_new = $tmpfile.".jpg";
`pngtopnm $tmpfile | pnmtojpeg >$tmpfile_new`;
`mv $tmpfile_new $tmpfile`;
$graph_type = "jpg";
}
else { $graph_type = "png"; }
# Since the graph images are raw png files, we need to encode them
$graph_img = b64encode_img($tmpfile);
verb("import_pnp_graph: Encoded Nagiosgraph image file, format: ".$graph_type."\n");
return $graph_img;
}
# ########################################################################
# language translated email subject: $lang{$land}
# ########################################################################
sub set_subject {
my $subject;
my $b64_sub = "";
# special base64 encoding is required for subject parts send in Japanese
if ($land eq "jp") {
$b64_sub = " =?utf-8?B?" . encode_base64("ホスト $o_hostname($o_hostgroup)は");
chomp $b64_sub;
$b64_sub = $b64_sub . "?= ";
}
# special base64 encoding is required for subject parts send in French
if ($land eq "fr") {
$b64_sub = " =?utf-8?B?" . encode_base64("d\'hôte $o_hostname ($o_hostgroup) est");
chomp $b64_sub;
$b64_sub = $b64_sub . "?= ";
}
my %lang = ('en' => "Nagios: $o_notificationtype Host $o_hostname ($o_hostgroup) is $o_hoststate",
'de' => "Nagios: $o_notificationtype System $o_hostname($o_hostgroup) ist $o_hoststate",
'jp' => "Nagios: $o_notificationtype" . $b64_sub . "$o_hoststate",
'fr' => "Nagios: $o_notificationtype" . $b64_sub . "$o_hoststate" );
if (!defined($lang{$land})) { $subject = $lang{'en'}; }
else { $subject = $lang{$land}; }
return $subject;
}
#########################################################################
# main
#########################################################################
check_options();
if (! defined ($o_notificationtype) && ! defined($o_test)) {
p_version();
print "\nError, no notification type available. Are you trying to send a test message?\n";
print "For a manual test from the commandline, we need to give the -t option.\n";
exit -1;
}
$mail{Cc} = $o_cc_recipients if ($o_cc_recipients);
$mail{Bcc} = $o_bcc_recipients if ($o_bcc_recipients);
$mail{smtp} = $o_smtphost;
$mail{subject} = set_subject();
# If the mail server requires authentication, try this line:
# $mail{auth} = {user => "<username>", password => "<mailpw>", method="">"LOGIN PLAIN", required=>1};
if ($o_format eq "graph") {
verb("main: trying to create the Nagiosgraph image.");
$graph_img = create_graph_image();
}
if ($o_format eq "multi" || $o_format eq "graph") {
verb("main: Sending HTML email (language: $land) with inline logo.");
# check if the logo file exists
if (-e $logofile) {
# In e-mails, images need to be base64 encoded, we encode the logo here
$logo_img = b64encode_img($logofile);
# extract the image format from the file extension
$logo_type = ($logofile =~ m/([^.]+)$/)[0];
verb("main: Converted logo data to base64 and set type to $logo_type.");
# create the second boundary marker for the logo
} else {
verb("main: Could not find logo file at $logofile, setting empty logo.");
# If the logo file cannot be found, we send a 1x1px empty logo image instead
$logo_img = $empty_img;
$logo_type = "gif";
}
create_boundary();
create_message_html();
$mail{'content-type'} = qq(multipart/related; boundary="$boundary");
$boundary = '--' . $boundary;
# Here we define the mail content to be send
my $mail_content = "This is a multi-part message in MIME format.\n"
# create the first boundary start marker for the main message
. "$boundary\n"
. "Content-Type: text/html; charset=utf-8\n"
. "Content-Transfer-Encoding: 8bit\n\n"
. "$html_msg\n";
# create the second boundary marker for the logo image
$mail_content = $mail_content . "$boundary\n"
. "Content-Type: image/$logo_type; name=\"logo.$logo_type\"\n"
. "Content-Transfer-Encoding: base64\n"
. "Content-ID: <$logo_id>\n"
. "Content-Disposition: inline; filename=\"logo.$logo_type\"\n\n"
. "$logo_img\n";
# if we got the graph format and a image has been generated, we add it here
# create the third boundary marker for the graph
if (defined($graph_img) && $o_format eq "graph") {
$mail_content = $mail_content . "\n"
. "$boundary\n"
. "Content-Type: image/$graph_type; name=\"graph.$graph_type\"\n"
. "Content-Transfer-Encoding: base64\n"
. "Content-ID: <$graph_id>\n"
. "Content-Disposition: inline; filename=\"graph.$graph_type\"\n\n"
. "$graph_img\n";
}
# create the final end boundary marker
$mail_content = $mail_content . $boundary . "--\n";
# put the completed message body into the mail
$mail{body} = $mail_content ;
}
elsif ($o_format eq "html") {
create_message_html();
$mail{'content-type'} = qq(text/html; charset="utf-8");
$mail{body} = $html_msg ;
} else {
create_message_text();
$mail{'content-type'} = qq(text/plain; charset="utf-8");
$mail{body} = $text_msg ;
}
sendmail(%mail) or die $Mail::Sendmail::error;
verb("Sendmail Log says:\n$Mail::Sendmail::log\n");
exit 0;
# #######################################################################
# Create a debugging table to check on Nagios and script variables
# Added by Robert Becht to create a HTML table for debugging
# #######################################################################
sub create_debugtable() {
my $varcount = 0;
my $oddcheck = "odd";
# Check if the following variables are defined
my %param_vars = (
'script' => { "title" => 'Script debug data',
"o_verb" => \$o_verb,
"o_version" => \$o_version,
"o_help" => \$o_help,
"o_smtphost" => \$o_smtphost,
"o_customer" => \$o_customer,
"o_to_recipients" => \$o_to_recipients,
"o_to_group" => \$o_to_group,
"o_cc_recipients" => \$o_cc_recipients,
"o_bcc_recipients" => \$o_bcc_recipients,
"o_format" => \$o_format,
"o_addurl" => \$o_addurl,
"o_language" => \$o_language,
"o_test" => \$o_test,
"o_smtphost" => \$o_smtphost,
"domain" => \$domain,
"land" => \$land,
"logo file" => \$logofile,
"logo format" => \$logo_type,
"temporary file" => \$tmpfile,
"boundary" => \$boundary },
'nagios' => { "title" => 'Nagios debug data',
"o_notificationtype" => \$o_notificationtype,
"o_notificationauth" => \$o_notificationauth,
"o_notificationcmt" => \$o_notificationcmt,
"o_hoststate" => \$o_hoststate,
"o_hostname" => \$o_hostname,
"o_hostalias" => \$o_hostalias,
"o_hostgroup" => \$o_hostgroup,
"o_hostaddress" => \$o_hostaddress,
"o_datetime" => \$o_datetime,
"o_hostoutput" => \$o_hostoutput,
"o_to_recipients" => \$o_to_recipients,
"o_to_group" => \$o_to_group },
'nagiosgraph' => { "title" => 'Nagiosgraph debug data',
"access URL" => \$ngraph_cgiurl,
"rrd_basedir" => \$rrd_basedir,
"graph_img_size" => \$graph_img_size,
"graph_bgcolor" => \$graph_bgcolor,
"graph_type" => \$graph_type } );
# loop to display the script variable tables
foreach $tbl (keys %param_vars) {
$debugtables .= "<br>\n"
. "<table width=$table_size>\n"
. "<tr><th colspan=2 class=customer>$param_vars{$tbl}->{'title'}</th></tr>\n";
$varcount = 0;
# Data loop
foreach $var (keys %{$param_vars{$tbl}}) {
if ($var ne 'title') {
if ($varcount%2) {$oddcheck = "odd";} else {$oddcheck = "even";}
$debugtables .= "<tr><th class=$oddcheck>$var</th>";
if ((! defined(${$param_vars{$tbl}->{$var}})) || (${$param_vars{$tbl}->{$var}} eq '')) {
$debugtables .= "<td class=$oddcheck> </td></tr>\n";
} else {
$debugtables .= "<td class=$oddcheck>${$param_vars{$tbl}->{$var}}</td></tr>\n";
}
$varcount++;
}
}
$debugtables .= "</table>";
$debugtables .="<br>\n";
}
}
# #################### End of nagios_send_host_mail.pl ####################
Eu tenho script acima para enviar e-mails personalizados em HTML com alertas do Nagios referentes a hosts. Esse script funciona normalmente. Envia um email para cada contato do nagios.
Porém o script abaixo - com a mesma funcionalidade porém para enviar emails de alertas de serviços do Nagios - não funciona como deveria. Ele enviar mais de um email - dependendo da quantidade de contatos - Ex: Preciso enviar o alerta do nagios para 4 emails, então ele envia o alerta para cada um dos contatos 4 vezes, outro problema é que ele ao invês de pegar o endereço de email de cada contato, ele pega o nome do contato e adiciona o sufixo @domain.com, ou seja, um usuário que o contato no nagios é joaojunior porém o email é joao@domain.com, o script acaba enviando email para joaojunior@domain.com. O script com problema está abaixo.
#!/usr/bin/perl -w
#
# First we explicitly switch off the Nagios embbeded Perl Interpreter
# nagios: -epn
# ######################### pnp4n_send_service_mail.pl ################ #
# Date : Mar 18 2012 #
# Purpose : Script to send out Nagios service e-mails.\n"; #
# Author : Frank Migge (support at frank4dd dot com), Robert Becht #
# Help : http://nagios.frank4dd.com/howto #
# Licence : GPL - http://www.fsf.org/licenses/gpl.txt #
# Written for and verified with Nagios version 3.2.3 #
# Help : ./pnp4n_send_service_mail.pl -h #
# #
# Version : 1.0 initial release #
# Version : 1.1 add multipart MIME and logo #
# Version : 1.2 cleanup mail body generation code #
# Version : 1.3 use environment variables for Nagios data handoff #
# Version : 1.4 add the performance graph image if available #
# this has been implemented for Nagiosgraph v0.9.1 #
# Version : 1.5 add -g for using $CONTACTGROUPMEMBERS$ macro #
# multi-language support for en|de|fr|jp, extendable #
# enhanced debug, version by Robert Becht #
# the script now reads logo's from file #
# #
# Depends : perl-Mail-Sendmail #
# perl-MIME-tools #
# rrdtool-devel #
# libnetpbm (if image conversion from PNG to JPG is required) #
# netpbm (if image conversion from PNG to JPG is required) #
# ##################################################################### #
use Getopt::Long;
use Mail::Sendmail;
use Digest::MD5 qw(md5_hex);
use MIME::Base64;
use RRDs;
use File::Temp;
use strict;
use warnings;
use vars qw( $o_verb $o_version $o_help $o_to_group
$o_cc_recipients $o_bcc_recipients $o_addurl $inputfile $ftemp
$logo_id $graph_id $rrdfile $tmpfile $land $debugtables $tbl $var %param_vars
$hs $G $elapse $tstamp $tstart $img_get $ds );
# The version of this script
my $Version ='1.6';
my $authors = 'Frank Migge, Robert Becht';
# the sender e-mail address to be seen by recipients
my $mail_sender = "Nagios Monitoring <nagiosadmin\@yourdomain>";
# The nagios CGI URL
my $nagios_cgiurl = "http://192.168.1.1/nagios/cgi-bin";
# Modified by Robert Becht that to use PNP4Nagios links
# The PNP4Nagios URL : il not use, simply make to equal 'undef'.
my $nagios_pnpurl = "http://192.168.1.1/pnp4nagios";
my ($ra, $rb, $rc, $pnp_uri) = split('/',$nagios_pnpurl); # Otherwise you can set $pnp_uri manualy
# Here we define a simple HTML stylesheet to be used in the HTML header.
my $html_style = "body {text-align: center; font-family: Verdana, sans-serif; font-size: 10pt;}\n"
. "img.logo {float: left; margin: 10px 10px 10px; vertical-align: middle}\n"
. "span {font-family: Verdana, sans-serif; font-size: 12pt;}\n"
. "table {text-align:center; margin-left: auto; margin-right: auto;}\n"
. "th {white-space: nowrap;}\n"
. "th.even {background-color: #D9D9D9;}\n"
. "td.even {background-color: #F2F2F2;}\n"
. "th.odd {background-color: #F2F2F2;}\n"
. "td.odd {background-color: #FFFFFF;}\n"
. "th,td {font-family: Verdana, sans-serif; font-size: 10pt; text-align:left;}\n"
. "th.customer {width: 600px; background-color: #004488; color: #ffffff;}";
my $table_size = "600px";
my $header_size = "180px";
my $data_size = "420px";
my $debugtables = "</br>\n";
# ########################################################################
# SMTP related data: If the commandline argument -H/--smtphost was not
# given, we use the provided value in $o_smtphost below as the default.
# ########################################################################
my $o_smtphost = "192.168.1.64";
my $domain = "\@yourdomain";
my @listaddress = ();
# ########################################################################
# This is the logo image file, the path must point to a valid JPG, GIF or
# PNG file, i.e. the nagios logo. Best size is rectangular up to 160x80px.
# example: [nagioshome]/share/images/NagiosEnterprises-whitebg-112x46.png
# ########################################################################
my $logofile = "/usr/lib64/nagios/local/logo_devsys.png";
# ########################################################################
# Here I define the HTML color values for each Nagios notification type.
# There is one extra called TEST for sending a test e-mail from the cmdline
# outside of Nagios. The color values are used for highlighting the
# background of the notification type cell.
# ########################################################################
my %NOTIFICATIONCOLOR=('PROBLEM'=>'#FF8080','RECOVERY'=>'#80FF80','ACKNOWLEDGEMENT'=>'FFFF80',
'DOWNTIMESTART'=>'80FFFF','DOWNTIMEEND'=>'80FF80','DOWNTIMECANCELLED'=>'FFFF80',
'FLAPPINGSTART'=>'#FF8080','FLAPPINGSTOP'=>'#80FF80',' FLAPPINGDISABLED'=>'FFFF80',
'TEST'=>'80FFFF');
# ########################################################################
# Here we set the information where to pick up the RRD data files for the
# optional graph image generation, plus the graph size width x height px
# ########################################################################
my $rrd_basedir = "/var/nagios/perfdata";
my $graph_img_size = "521x60";
my $graph_bgcolor = "#F2F2F2";
my $graph_border = "#999999";
# ########################################################################
# language translated message text: $language{$land}{'A'} (=Customer)
# You can simply add here your translation...
# ########################################################################
my %language = ('en' => { 'A' => 'Customer',
'B' => 'Notification Type',
'C' => 'Service Name',
'D' => 'Service Status',
'E' => 'Service Group',
'F' => 'Service Data',
'G' => 'Hostname',
'H' => 'Hostalias',
'I' => 'IP Address',
'J' => 'Hostgroup',
'K' => 'Event Time',
'L' => 'Author',
'M' => 'Comment',
'N' => 'Nagios Monitoring System Notification',
'O' => 'Generated by Nagios, the OpenSource monitoring solution' },
'fr' => { 'A' => 'Utilisateur',
'B' => 'Type de notification',
'C' => 'Nom du service',
'D' => 'Statut du service',
'E' => 'Groupe du service',
'F' => 'Données',
'G' => 'Nom d\'hôte',
'H' => 'Alias d\'hôte',
'I' => 'Adresse IP',
'J' => 'Groupe d\'hôte',
'K' => 'Heure de la notification',
'L' => 'Auteur',
'M' => 'Commentaire',
'N' => 'Notification de la surveillance Nagios',
'O' => 'Généré par Nagios, le système de surveillance OpenSource' },
'de' => { 'A' => 'Anwender',
'B' => 'Nachrichtentyp',
'C' => 'Dienstname',
'D' => 'Dienstzustand',
'E' => 'Dienstgruppe',
'F' => 'Dienstinformationen',
'G' => 'Systemname',
'H' => 'Systemalias',
'I' => 'System IP Adresse',
'J' => 'Systemgruppe',
'K' => 'Meldungsdatum',
'L' => 'Author',
'M' => 'Kommentar',
'N' => 'Nagios Überwachungssytem Meldung',
'O' => 'Erstellt mit Nagios, dem OpenSource Überwachungssytem' },
'jp' => { 'A' => '顧客名',
'B' => '通知の種類',
'C' => 'サービス名',
'D' => 'サービスの状態',
'E' => 'サービスグループ',
'F' => 'サービスデータ出力',
'G' => 'ホスト名',
'H' => 'ホストの別名',
'I' => 'IPアドレス',
'J' => 'ホストグループ',
'K' => 'イベントの日付と時刻',
'L' => '投稿者',
'M' => 'コメント',
'N' => 'Nagios 監視システムの通知',
'O' => 'このメーセジはオープンソースの監視システムNagiosで生成されています。' });
####### Global Variables - No changes necessary below this line ##########
# Nagios notification type, i.e. PROBLEM
my $o_notificationtype = $ENV{NAGIOS_NOTIFICATIONTYPE};
# Nagios notification author (if avail.)
my $o_notificationauth = $ENV{NAGIOS_NOTIFICATIONAUTHOR};
# Nagios notification comment (if avail.)
my $o_notificationcmt = $ENV{NAGIOS_NOTIFICATIONCOMMENT};
# Nagios service description
my $o_servicedesc = $ENV{NAGIOS_SERVICEDESC};
# Nagios service state
my $o_servicestate = $ENV{NAGIOS_SERVICESTATE};
# Nagios service group the service belongs to
my $o_servicegroup = $ENV{NAGIOS_SERVICEGROUPNAME};
# Nagios monitored host name
my $o_hostname = $ENV{NAGIOS_HOSTNAME};
# Nagios monitored host alias
my $o_hostalias = $ENV{NAGIOS_HOSTALIAS};
# Nagios host group the host belongs to
my $o_hostgroup = $ENV{NAGIOS_HOSTGROUPNAME};
# Nagios monitored host IP address
my $o_hostaddress = $ENV{NAGIOS_HOSTADDRESS};
# Nagios service check output data
my $o_serviceoutput = $ENV{NAGIOS_SERVICEOUTPUT};
# Nagios date when the event was recorded
my $o_datetime = $ENV{NAGIOS_LONGDATETIME};
# The recipients defined in $CONTACTEMAIL$
my $o_to_recipients = $ENV{NAGIOS_CONTACTEMAIL};
# Modified by Robert Becht for using $CONTACTGROUPEMEMBERS$ in nagios.conf
my $o_to_group = $ENV{NAGIOS_CONTACTGROUPMEMBERS};
# The next variables are provided through args
my $o_cc_recipients = undef; # The recipients defined in $CONTACTADDRESS1$
my $o_bcc_recipients = undef; # The recipients defined in $CONTACTADDRESS2$
my $o_format = "text";# The e-mail output format (default: text)
my $o_addurl = undef; # flag to add Nagios GUI URLs to HTML e-mails
my $o_language = undef; # The e-mail output language
my $o_lang_def = "en"; # The e-mail output language default
my $o_customer = undef; # Company name and contract number for service providers
my $o_help = undef; # We want help
my $o_verb = undef; # verbose mode
my $o_version = undef; # print version
my $o_test = undef; # generate a test message
# These variables are used in various subroutines
my $text_msg = undef; # the plaintext notification
my $html_msg = undef; # the HTML-formatted notification
my $graphfile = undef; # if we generate graphs, the tmp file location
my @rrd;
my $logo_img = undef; # base64-encoded logo
my $graph_img = undef; # base64-encoded graph
my $boundary = undef; # unique string for multi-part emails
my %mail;
# ########################################################################
# subroutine defintions below
# ########################################################################
# ########################################################################
# p_version returns the program version
# ########################################################################
sub p_version { print "$0 nagios_send_service_mail.pl version : $Version\n"; }
# ########################################################################
# print_usage returns the program usage
# ########################################################################
sub print_usage {
print "Usage: $0 [-v] [-V] [-h] [-t] [-H <SMTP host>] [-p <customername>]
[-r <to_recipients> or -g <to_group>] [-c <cc_recipients>] [-b <bcc_recipients>]
[-f <text|html|multi|graph>] [-u] [-l <en|jp|fr|de|(or other languages if added)]\n";
}
# ########################################################################
# help returns the program help message
# ########################################################################
sub help {
print "\nNagios e-mail notification script for service events, version ",$Version,"\n";
print "GPL licence, (c)2010 Frank Migge\n\n";
print_usage();
print <<EOT;
This script takes over the Nagios e-mail notifications by receiving the Nagios state information,
formatting the e-mail and sending it out through an SMTP gateway.
-v, --verbose
print extra debugging information
-V, --version
prints version number
-h, --help
print this help message
-t, --test
generates a test message together with -r, --to-recipients
-H, --smtphost=HOST
name or IP address of SMTP gateway
-p, --customer="customer name and contract #"
optionally, add the customer name and contract for service providers
-r, --to-recipients
this option overrides the Nagios-provided \$CONTACTEMAIL\$ list of to: recipients
-g, --to-group-recipients \$CONTACTGROUPMEMBERS\$
this option use the list of contactgroup and reconstitutes the mail address with the hard defined \$domain
in this script. This is only possible when the contact name "abcd" works under the address "abcd\@domain".
-c, --cc-recipients
the Nagios-provided \$CONTACTADDRESS1\$ list of cc: recipients
-b, --bcc-recipients
the Nagios-provided \$CONTACTADDRESS2\$ list of bcc: recipients
-f, --format='text|html|multi|graph'
the email format to generate: either plain text,, HTML,
multipart S/MIME and multipart adding the Nagiosgraph image
-u, --addurl
this adds URL's to the Nagios web GUI for check status,
host and hostgroup views into the html mail,
requires -f html or -f multi
-l, --language='en|jp|fr|de|(or what you defined in this script)'
the prefered e-mail language. The content-type header is currently is hard-coded to UTF-8.
This might need to be changed if recipients require a different characterset encoding.
Extra: For useful debug output, go to Nagios, select a service and choose "Send custom service notification".
Entering text including the word "email-debug" in the comment field will trigger the creation of additional
tables with a list of Nagios and script variables.
EOT
}
# ########################################################################
# verb creates verbose output
# ########################################################################
sub verb {
my $t=shift;
print $t,"\n" if defined($o_verb);
}
# ########################################################################
# unique content ID are needed for multipart messages with inline logos
# ########################################################################
sub create_content_id {
my $unique_string = rand(100);
$unique_string = $unique_string . substr(md5_hex(time()),0,23);
$unique_string =~ s/(.{5})/$1\./g;
my $content_id = qq(part.${unique_string}\@) . "MAIL";
$unique_string = undef;
return $content_id;
}
# ########################################################################
# create_boundary creates the S/MIME multipart boundary strings
# ########################################################################
sub create_boundary {
my $unique_string = substr(md5_hex(time()),0,24);
$boundary = '======' . $unique_string ;
$unique_string = undef;
}
sub unknown_arg {
print_usage();
exit -1;
}
# ########################################################################
# create_address from the groupmembers list (Add by Robert Becht)
# ########################################################################
sub create_address {
chomp($o_to_group);
my @mlist = split(",",$o_to_group);
foreach (@mlist) {
my $maddress = "$_"."$domain";
# Debugging
#print "$maddress\n";
push(@listaddress,$maddress);
}
$o_to_group = join(",",@listaddress);
#Debugging
#print "$o_to_group\n";
return ($o_to_group);
}
# ########################################################################
# check_options checks and processes the commandline options given
# ########################################################################
sub check_options {
Getopt::Long::Configure ("bundling");
GetOptions(
'v' => \$o_verb, 'verbose' => \$o_verb,
'V' => \$o_version, 'version' => \$o_version,
'h' => \$o_help, 'help' => \$o_help,
't' => \$o_test, 'test' => \$o_test,
'H:s' => \$o_smtphost, 'smtphost:s' => \$o_smtphost,
'p:s' => \$o_customer, 'customer:s' => \$o_customer,
'r:s' => \$o_to_recipients, 'to-recipients:s' => \$o_to_recipients,
'g:s' => \$o_to_group, 'to-group-recipients' => \$o_to_group,
'c:s' => \$o_cc_recipients, 'cc-recipients:s' => \$o_cc_recipients,
'b:i' => \$o_bcc_recipients, 'bcc-recipients:s' => \$o_bcc_recipients,
'f:s' => \$o_format, 'format:s' => \$o_format,
'u' => \$o_addurl, 'addurl' => \$o_addurl,
'l:s' => \$o_language, 'language:s' => \$o_language
) or unknown_arg();
# Basic checks
if (defined ($o_help)) { help(); exit 0};
if (defined($o_version)) { p_version(); exit 0};
if ((! defined($o_to_recipients)) && (! defined($o_to_group))) { # no recipients provided
print "Error: no recipients have been provided\n"; print_usage(); exit -1}
else {
if (! defined($o_to_group)) {
%mail = ( To => $o_to_recipients,
From => $mail_sender,
Sender => $mail_sender ); }
else { &create_address;
%mail = ( To => $o_to_group,
From => $mail_sender,
Sender => $mail_sender ); }
}
if ( $o_format ne "text" && $o_format ne "html"
&& $o_format ne "multi" && $o_format ne "graph") # wrong mail format
{ print "Error: wrong e-mail format.\n"; print_usage(); exit -1}
if (defined($o_addurl) && $o_format eq "text")
{ print "Error: cannot add URL's to text.\n"; print_usage(); exit -1}
if (defined($o_test)) { create_test_data(); };
# Modified by Robert Becht to support additional languages
# if no language has been requested, try to determine default from OS
if (! defined($o_language)) {
# if environment $LANG is set, try to extract the first two country chars, i.e. "en|de|fr"
if ($ENV{LANG} eq "C" || $ENV{LANG} eq "POSIX") { $land = "en"; }
else { ($land, my $rem) = split('_',$ENV{LANG}, 2); }
} else { $land = $o_language; }
# Last resort: Set "English" if the requested language is not supported by our script
if (! $language{$land}{'A'}) { $land = $o_lang_def; }
}
# ########################################################################
# if -t or --test, we need to create sample test data to send out
# In order to successfully test a e-mail with performance graph generation
# set a valid hostname and servicedesc to be able to pick up a RRD file.
# ########################################################################
sub create_test_data {
if (! defined($o_customer)){ $o_customer = "ACME Corporation";}
if (! defined($o_notificationtype)){ $o_notificationtype = "TEST";}
if (! defined($o_servicestate)){ $o_servicestate = "UNKNOWN";}
if (! defined($o_hostname)){ $o_hostname = "susie114";}
if (! defined($o_hostalias)){ $o_hostalias = "susie114.frank4dd.com (LINUX)";}
if (! defined($o_hostaddress)){ $o_hostaddress = "127.0.0.1";}
if (! defined($o_hostgroup)){ $o_hostgroup = "Linux Servers";}
if (! defined($o_servicedesc)){ $o_servicedesc = "os_cpu_load";}
if (! defined($o_servicegroup)){ $o_servicegroup = "performance checks";}
if (! defined($o_datetime)){ $o_datetime = `date`;}
# if (! defined($o_datetime)) {$o_datetime = localtime time;}
if (! defined($o_serviceoutput)){ $o_serviceoutput = "Test output for this service";}
if (! defined($o_notificationauth)){ $o_notificationauth = "John Doe";}
# Setting the keyword "email-debug" in the notification comment below triggers the creation of debug tables
if (! defined($o_notificationcmt)){ $o_notificationcmt = "Test message for the service with email-debug";}
}
# ########################################################################
# Create a plaintext message -> $text_msg
# ########################################################################
sub create_message_text {
$text_msg = $language{$land}{'N'}."\n"
. "=====================================\n\n";
# if customer name was given for service providers, display it here
if ( defined($o_customer)) {
$text_msg = $text_msg . $language{$land}{'A'} . ": $o_customer\n";
}
$text_msg = $text_msg
. $language{$land}{'B'} . ": $o_notificationtype\n"
. $language{$land}{'C'} . ": $o_servicedesc\n"
. $language{$land}{'D'} . ": $o_servicestate\n"
. $language{$land}{'E'} . ": $o_servicegroup\n"
. $language{$land}{'F'} . ": $o_serviceoutput\n\n"
. $language{$land}{'G'} . ": $o_hostname\n"
. $language{$land}{'H'} . ": $o_hostalias\n"
. $language{$land}{'I'} . ": $o_hostaddress\n"
. $language{$land}{'J'} . ": $o_hostgroup\n"
. $language{$land}{'K'} . ": $o_datetime\n\n";
# if author and comment data has been passed from nagios
# and these variables have content, then we add two more columns
if ( ( defined($o_notificationauth) && defined($o_notificationcmt) ) &&
( ($o_notificationauth ne "") && ($o_notificationcmt ne "") ) ) {
$text_msg = $text_msg . $language{$land}{'L'} . ": $o_notificationauth\n"
. $language{$land}{'M'} . ": $o_notificationcmt\n\n";
}
$text_msg = $text_msg . "-------------------------------------\n"
. $language{$land}{'O'} . ".\n" . "(". $authors . ")\n" ;
}
# ########################################################################
# Create a simple HTML message -> $html_msg
# ########################################################################
sub create_message_html {
# Start HTML message definition
$html_msg = "<html><head><style type=\"text/css\">$html_style</style></head><body>\n"
. "<table width=$table_size><tr>\n";
if ($o_format eq "multi" || $o_format eq "graph") {
$logo_id = create_content_id();
$html_msg = $html_msg . "<td><img class=\"logo\" src=\"cid:$logo_id\"></td>"
. "<td><span>$language{$land}{'N'}</span></td></tr><tr>\n";
} else {
$html_msg = $html_msg
. "<th colspan=2><span>$language{$land}{'N'}</span></th></tr><tr>\n"; }
if ( defined($o_customer)) {
$html_msg = $html_msg
. "<th colspan=2 class=customer>$o_customer</th></tr><tr>\n"; }
$html_msg = $html_msg
. "<th width=$header_size class=even>$language{$land}{'B'}:</th>\n"
. "<td bgcolor=$NOTIFICATIONCOLOR{$o_notificationtype}>\n"
. "$o_notificationtype</td></tr>\n"
. "<tr><th class=odd>$language{$land}{'C'}:</th><td>$o_servicedesc</td></tr>\n"
. "<tr><th class=even>$language{$land}{'E'}:</th><td class=even>\n";
# The Servicegroup URL http://<nagios-web>/cgi-bin/status.cgi?servicegroup=$SERVICEGROUPNAME$&style=overview
# This URL shows the service group table listing ofthe hosts that have this service
if (defined($o_addurl)) {
$html_msg = $html_msg
. "<a href=\"$nagios_cgiurl/status.cgi?servicegroup=$o_servicegroup&style=overview\">$o_servicegroup</a>";
} else { $html_msg = $html_msg . $o_servicegroup; }
$html_msg = $html_msg . "</td></tr>\n"
. "<tr><th class=odd>$language{$land}{'D'}:</th><td>$o_servicestate</td></tr>\n"
. "<tr><th class=even>$language{$land}{'F'}:</th><td class=even>\n";
# The ServiceOutput URL http://<nagios-web>/cgi-bin/extinfo.cgi?type=2&host=$HOSTNAME$&service=$SERVICEDESC$
# This URL shows the full service details and commands for service management (ack, re-check, disable, etc)
if (defined($o_addurl)) {
if ( $nagios_pnpurl eq '') {
$html_msg .= "<a href=\"$nagios_cgiurl/extinfo.cgi?type=2&host=$o_hostname&service=$o_servicedesc\">$o_serviceoutput</a>\n";
} else {
# Modified by Robert Becht for link to PNP4Nagios graph
$html_msg .= "<a href=\"$nagios_pnpurl/index.php/graph?host=$o_hostname&srv=$o_servicedesc\">$o_serviceoutput</a>\n"; }
} else{ $html_msg .= $o_serviceoutput; }
$html_msg = $html_msg . "</td></tr>\n"
. "<tr><th class=odd>$language{$land}{'G'}:</th><td>\n";
# The Hostname URL http://<nagios-web>/cgi-bin/status.cgi?host=$HOSTNAME$&style=detail
# this URL shows the host and all services underneath it
if (defined($o_addurl)) {
$html_msg = $html_msg
. "<a href=\"$nagios_cgiurl/status.cgi?host=$o_hostname&style=detail\">$o_hostname</a>";
} else { $html_msg = $html_msg . $o_hostname; }
$html_msg = $html_msg . "</td></tr>\n"
. "<tr><th class=even>$language{$land}{'H'}:</th><td class=even>$o_hostalias</td></tr>\n"
. "<tr><th class=odd>$language{$land}{'I'}:</th><td>$o_hostaddress</td></tr>\n"
. "<tr><th class=even>$language{$land}{'J'}:</th><td class=even>\n";
# The Hostgroup URL http://<nagios-web>/cgi-bin/status.cgi?hostgroup=$HOSTGROUPNAME$&style=overview
# This URL shows the hostgroup table listing for all individual hosts that belong to it
if (defined($o_addurl)) {
$html_msg = $html_msg
. "<a href=\"$nagios_cgiurl/status.cgi?hostgroup=$o_hostgroup&style=overview\">$o_hostgroup</a>";
} else { $html_msg = $html_msg . $o_hostgroup; }
$html_msg = $html_msg . "</td></tr>\n"
. "<tr><th class=odd>$language{$land}{'K'}:</th><td>$o_datetime</td></tr>\n";
# If the author and comment data has been passed from nagios
# and these variables have content, then we add two more columns
if ( ( defined($o_notificationauth) && defined($o_notificationcmt) ) &&
( ($o_notificationauth ne "") && ($o_notificationcmt ne "") ) ) {
$html_msg = $html_msg . "<tr><th class=even>$language{$land}{'L'}:</th>\n"
. "<td class=even>$o_notificationauth</td></tr>\n"
. "<tr><th class=odd>$language{$land}{'M'}:</th>\n"
. "<td>$o_notificationcmt</td></tr>\n";
}
$html_msg = $html_msg . "</table></br>\n";
# if we got the graph format and a image has been generated, we add it here
if (defined($graph_img) && $o_format eq "graph") {
$graph_id = create_content_id();
$html_msg = $html_msg . "<img src=\"cid:$graph_id\">\n";
}
# add the Nagios footer tag line here
$html_msg = $html_msg . "</br><hr>\n$language{$land}{'O'}\n
.</br><em><font size=\"-1\" >(Authors:$authors)</font></em><hr>\n";
# add the extra debugtables if verbose output had been requested,
# or if the notification command contains the keyword "email-debug"
if (defined($o_notificationcmt) && ($o_notificationcmt =~ m/email-debug/i)
|| defined($o_verb)) {
&create_debugtable;
$html_msg = $html_msg . $debugtables;
}
# End HTML message definition
$html_msg = $html_msg . "</body></html>\n";
}
# #######################################################################
# urlencode() URL encode a string
# #######################################################################
sub urlencode {
$_[0] =~ s/([\W])/"%" . uc(sprintf("%2.2x",ord($1)))/eg;
return $_[0];
}
# #######################################################################
# hashcolor() Choose a color for service
# #######################################################################
sub hashcolor {
my $c=0;
map{$c=(51*$c+ord)%(216)}split//,"$_[0]x";
my $i = 0;
my $n = 0;
my $m = 0;
my @h=(51*int $c/36,51*int $c/6%6,51*($c%6));
for$i(0..2){$m=$i if$h[$i]<$h[$m];$n=$i if$h[$i]>$h[$n]}
$h[$m]=102if$h[$m]>102;$h[$n]=153if$h[$n]<153;
$c=sprintf"%06X",$h[2]+$h[1]*256+$h[0]*16**4;
return $c;
}
# #######################################################################
# dbfilelist() Get list of matching rrd files
# #######################################################################
sub dbfilelist {
my($host,$service, $rrddir) = @_;
my $hs;
# New style, files inside a <hostname> directory
$rrddir .= "/" . $host;
$hs = urlencode "$service" . "___";
verb("sub dbfilelist: Checking files inside directory: ".$rrddir);
my @rrd;
opendir DH, $rrddir or verb("sub dbfilelist: Cannot open: ".$rrddir);
@rrd = grep s/^${hs}(.+)\.rrd$/$1/, readdir DH;
closedir DH;
verb("sub dbfilelist: We found number of RRD files: ".@rrd);
return @rrd;
}
# #######################################################################
# graphinfo() Find graphs and values
# #######################################################################
sub graphinfo {
my($host,$service,$rrddir) = @_;
my(@rrd,$ds,$f,$dsout,@values,$hs,%H,%R);
$hs = $host . "/";
$hs .= urlencode "$service" . "___";
# Determine which files to read lines from
@rrd = map {{ file=>$_ }}
map { "${hs}${_}.rrd" }
dbfilelist($host,$service, $rrddir);
# we stop processing here if we could not find a file
if (@rrd < 1) {
verb("sub graphinfo: Could not find any graph file.");
return undef;
} else {
verb("sub graphinfo: Listing $hs db files in $rrddir: "
. join ', ', map { $_->{file} } @rrd);
}
$rrdfile = $rrd[0]->{file};
$ds = RRDs::info "$rrddir/$rrdfile";
verb("sub graphinfo: RRDs::info ERR " . RRDs::error) if RRDs::error;
map { $rrd[0]->{line}{$_} = 1}
grep {!$H{$_}++}
map { /ds\[(.*)\]/; $1 }
grep /ds\[(.*)\]/,
keys %$ds;
verb("sub graphinfo: Found datasources: " . %$ds);
return \@rrd;
}
# #######################################################################
# rrdline() Generate the rrd parameters to produce a graph
# #######################################################################
sub rrdline {
my($host,$service,$geom,$G,$rrddir,$tmpfile) = @_;
my($g,$f,$v,$c,@ds);
my $directory = $rrddir;
@ds = ($tmpfile, '-a', 'PNG', '-t', $service);
push @ds, "--color=BACK$graph_bgcolor",
"--color=SHADEA$graph_border",
"--color=SHADEB$graph_border";
# Identify where to pull data from and what to call it
for $g ( @$G ) {
$f = $g->{file};
verb("sub rrdline: set filename: $f");
# Compute the longest label length
my $longest = (sort map(length,keys(%{ $g->{line} })))[-1];
for $v ( sort keys %{ $g->{line} } ) {
$c = hashcolor($v);
verb("sub rrdline: file=$f line=$v color=$c");
my $sv = "$v";
my $label = sprintf("%-${longest}s", $sv);
push @ds , "DEF:$sv=$directory/$f:$v:AVERAGE"
, "LINE2:${sv}#$c:$label";
my $format = '%6.2lf%s';
# Graph labels
push @ds, "GPRINT:$sv:MAX:Max\\: $format"
, "GPRINT:$sv:AVERAGE:Avg\\: $format"
, "GPRINT:$sv:MIN:Min\\: $format"
, "GPRINT:$sv:LAST:Cur\\: ${format}\\n";
}
}
# Dimensions of graph if geom is specified
if ( $geom ) {
my($w,$h) = split 'x', $geom;
push @ds, '-w', $w, '-h', $h;
}
return @ds;
}
# ########################################################################
# uuencode_image(filename) converts a existing binary source image file
# into a base64-image string.
# ########################################################################
sub uuencode_img {
my($inputfile) = @_;
open (IMG, $inputfile) or verb("uuencode_img: Cannot read source image file: $inputfile - $!");
binmode IMG; undef $/;
my $uuencoded_img = encode_base64(<IMG>);
close IMG;
verb("uuencode_img: completed conversion of source image file: $inputfile - $!");
return $uuencoded_img;
}
# #######################################################################
# create_graph_img() tries to create a performance graph image file (PNG)
# Input is the hostname and servicename, then we try to find a matching
# RRD file according to NagiosGraph's filesystem layout. If there is one,
# it queries the RRD information and graphs the last 24 hours similar to
# Nagiosgraph.
# #######################################################################
sub create_graph_img {
my $fhandle = undef;
my $graph_img = undef;
# Figure out db files and line labels
my $G = graphinfo($o_hostname,$o_servicedesc,$rrd_basedir);
# if we could not find RRD data, we return $img as undef
if(! defined($G)) {
verb("sub create_graph_img: No graph data for $o_hostname,$o_servicedesc was found.");
return $graph_img;
}
# generate temporary graph files for todays RRD data
$fhandle = File::Temp->new() or verb("create_graph_img: Cannot create temporary image file.");
my $tmpfile = $fhandle->filename;
$ftemp = $tmpfile;
my @ds = rrdline($o_hostname,$o_servicedesc,$graph_img_size,$G,$rrd_basedir,$tmpfile);
verb("sub create_graph_img: RRDs::graph ". join ' ', @ds);
RRDs::graph(@ds);
verb("sub create_graph_img: RRDs::graph ERR " . RRDs::error) if RRDs::error;
# because our mail system being Lotus Notes, which is not supporting PNG
# images, we must convert them from PNG to JPG before we can continue.
# comment out the next 3 lines if PNG images work with your mail clients
# my $jpg_tmpfile = $tmpfile.".jpg";
# `pngtopnm $tmpfile | pnmtojpeg >$jpg_tmpfile`;
# `mv $jpg_tmpfile $tmpfile`;
# In e-mails, images need to be base64 encoded, we uuencode here
$graph_img = uuencode_img($tmpfile);
return $graph_img;
}
# ########################################################################
# Added by Robert Becht for request an PNP4Nagios graph
# ########################################################################
sub import_pnp_graph {
use LWP::Simple;
$elapse = (1 * 3600); # This set 1 hour history
$tstamp = time();
$tstart = ($tstamp - $tstamp);
$img_get = "http://127.0.0.1/$pnp_uri/image?host=$o_hostname&srv=$o_servicedesc&source=0&start=$tstart&end=$tstamp";
# generate temporary graph files for todays RRD data
my $fhandle = File::Temp->new( UNLINK =>1, SUFFIX => '.png') or verb("create_graph_img: Cannot create temporary image file.");
my $tmpfile = $fhandle->filename;
$ftemp = $tmpfile;
# write the graphik file in $tmpfile
print $fhandle get("$img_get");
# This is for graph size
my $pnmfile = `pngtopnm $tmpfile`;
(my $xysize = $graph_img_size) =~ s/x/ /;
`pamscale -xysize $xysize $pnmfile | pnmtopng >$img_get`; # or use pnmtojpeg if png not supported ...
$graph_img = uuencode_img($tmpfile);
return $graph_img;
}
# ########################################################################
# language translated email subject: $lang{$land}
# ########################################################################
sub set_subject {
my $subject;
my %lang = ('en' => "Nagios: $o_notificationtype service $o_servicedesc on $o_hostname ($o_hostgroup) is $o_servicestate",
'de' => "Nagios: $o_notificationtype $o_hostname($o_hostgroup) mit Dienst $o_servicedesc ist $o_servicestate",
'jp' => "Nagios: $o_notificationtype $o_hostname($o_hostgroup)のサービス $o_servicedesc $o_servicestate",
'fr' => "Nagios: $o_notificationtype : le service $o_servicedesc sur $o_hostname ($o_hostgroup) est $o_servicestate" );
if (!defined($lang{$land})) { $subject = $lang{'en'}; }
else { $subject = $lang{$land}; }
return $subject;
}
# #######################################################################
# main
# #######################################################################
check_options();
$mail{Cc} = $o_cc_recipients if ($o_cc_recipients);
$mail{Bcc} = $o_bcc_recipients if ($o_bcc_recipients);
$mail{smtp} = $o_smtphost;
$mail{subject} = set_subject();
# If the mail server requires authentication, try this line:
# $mail{auth} = {user => "<username>", password => "<mailpw>", method="">"LOGIN PLAIN", required=>1};
if ($o_format eq "graph") {
if ( ! defined $pnp_uri) {
verb("main: trying to create the a graph image.");
$graph_img = create_graph_img();
} else { $graph_img = import_pnp_graph();}
}
if ($o_format eq "multi" || $o_format eq "graph") {
verb("main: Sending HTML email (language: $land) with inline logo.");
# In e-mails, images need to be base64 encoded, we uuencode here
my $logo_img = uuencode_img($logofile);
create_boundary();
create_message_html();
$mail{'content-type'} = qq(multipart/related; boundary="$boundary");
$boundary = '--' . $boundary;
# Here we define the mail content to be send
my $mail_content = "This is a multi-part message in MIME format.\n"
# create the first boundary start marker for the main message
. "$boundary\n"
. "Content-Type: text/html; charset=utf-8\n"
. "Content-Transfer-Encoding: 8bit\n\n"
. "$html_msg\n";
# create the second boundary marker for the logo
$mail_content = $mail_content . "$boundary\n"
. "Content-Type: image/gif; name=\"logo.gif\"\n"
. "Content-Transfer-Encoding: base64\n"
. "Content-ID: <$logo_id>\n"
. "Content-Disposition: inline; filename=\"logo.gif\"\n\n"
. "$logo_img\n";
# if we got the graph format and a image has been generated, we add it here
# create the third boundary marker for the graph
if (defined($graph_img) && $o_format eq "graph") {
$mail_content = $mail_content . "\n"
. "$boundary\n"
. "Content-Type: image/jpg; name=\"graph.jpg\"\n"
. "Content-Transfer-Encoding: base64\n"
. "Content-ID: <$graph_id>\n"
. "Content-Disposition: inline; filename=\"graph.jpg\"\n\n"
. "$graph_img\n";
}
# create the final end boundary marker
$mail_content = $mail_content . $boundary . "--\n";
# put the completed message body into the mail
$mail{body} = $mail_content ;
}
elsif ($o_format eq "html") {
create_message_html();
$mail{'content-type'} = qq(text/html; charset="utf-8");
$mail{body} = $html_msg ;
} else {
create_message_text();
$mail{'content-type'} = qq(text/plain; charset="utf-8");
$mail{body} = $text_msg ;
}
sendmail(%mail) or die $Mail::Sendmail::error;
verb("Sendmail Log says:\n$Mail::Sendmail::log\n");
exit 0;
# #######################################################################
# Create a debugging table to check on Nagios and script variables
# Added by Robert Becht to create a HTML table for debugging
# #######################################################################
sub create_debugtable() {
my $varcount = 0;
my $oddcheck = "odd";
# Check if the following variables are defined
my %param_vars = (
'script' => { "title" => 'Script debug data',
"o_verb" => \$o_verb,
"o_version" => \$o_version,
"o_help" => \$o_help,
"o_smtphost" => \$o_smtphost,
"o_customer" => \$o_customer,
"o_to_recipients" => \$o_to_recipients,
"o_to_group" => \$o_to_group,
"o_cc_recipients" => \$o_cc_recipients,
"o_bcc_recipients" => \$o_bcc_recipients,
"o_format" => \$o_format,
"o_addurl" => \$o_addurl,
"o_language" => \$o_language,
"o_test" => \$o_test,
"o_smtphost" => \$o_smtphost,
"domain" => \$domain,
"land" => \$land,
"logo file" => \$logofile,
"temporary file" => \$ftemp,
"boundary" => \$boundary },
'nagios' => { "title" => 'Nagios debug data',
"o_notificationtype" => \$o_notificationtype,
"o_notificationauth" => \$o_notificationauth,
"o_notificationcmt" => \$o_notificationcmt,
"o_servicedesc" => \$o_servicedesc,
"o_servicestate" => \$o_servicestate,
"o_servicegroup" => \$o_servicegroup,
"o_hostname" => \$o_hostname,
"o_hostalias" => \$o_hostalias,
"o_hostgroup" => \$o_hostgroup,
"o_hostaddress" => \$o_hostaddress,
"o_serviceoutput" => \$o_serviceoutput,
"o_datetime" => \$o_datetime,
"o_to_recipients" => \$o_to_recipients,
"o_to_group" => \$o_to_group },
'rrdbase' => { "title" => 'RRD debug data',
"rrd_basedir" => \$rrd_basedir,
"rrdfile" => \$rrdfile,
"hs" => \$hs,
"rrdfile" => \$rrdfile,
"DS" => \$ds,
"labels" => \$G },
'pnp' => { "title" => 'PNP debug data',
"PNP url" => \$nagios_pnpurl,
"PNP uri" => \$pnp_uri,
"img_get" => \$img_get,
"interval(s)" => \$elapse,
"time start" => \$tstamp } );
# display the script variables
# Tables loop
foreach $tbl (keys %param_vars) {
$debugtables .= "</br>\n"
. "<table width=$table_size>\n"
. "<tr><th colspan=2 class=customer>$param_vars{$tbl}->{'title'}</th></tr>\n";
$varcount = 0;
# Data loop
foreach $var (keys %{$param_vars{$tbl}}) {
if ($var ne 'title') {
if ($varcount%2) {$oddcheck = "odd";
} else {$oddcheck = "even";}
$debugtables .= "<tr><th class=$oddcheck>$var</th>";
if ((! defined(${$param_vars{$tbl}->{$var}})) || (${$param_vars{$tbl}->{$var}} eq '')) {
$debugtables .= "<td class=$oddcheck> </td></tr>\n";
} else {
$debugtables .= "<td class=$oddcheck>${$param_vars{$tbl}->{$var}}</td></tr>\n";
# # Debugging
# print $var . "= " . ${$param_vars{$tbl}->{$var}} . "\n";
}
$varcount++;
}
}
$debugtables .= "</table>";
$debugtables .="</br>\n";
}
}
#!/usr/bin/perl -w
#
# First we explicitly switch off the Nagios embbeded Perl Interpreter
# nagios: -epn
# ######################### pnp4n_send_service_mail.pl ################ #
# Date : Mar 18 2012 #
# Purpose : Script to send out Nagios service e-mails.\n"; #
# Author : Frank Migge (support at frank4dd dot com), Robert Becht #
# Help : http://nagios.frank4dd.com/howto #
# Licence : GPL - http://www.fsf.org/licenses/gpl.txt #
# Written for and verified with Nagios version 3.2.3 #
# Help : ./pnp4n_send_service_mail.pl -h #
# #
# Version : 1.0 initial release #
# Version : 1.1 add multipart MIME and logo #
# Version : 1.2 cleanup mail body generation code #
# Version : 1.3 use environment variables for Nagios data handoff #
# Version : 1.4 add the performance graph image if available #
# this has been implemented for Nagiosgraph v0.9.1 #
# Version : 1.5 add -g for using $CONTACTGROUPMEMBERS$ macro #
# multi-language support for en|de|fr|jp, extendable #
# enhanced debug, version by Robert Becht #
# the script now reads logo's from file #
# #
# Depends : perl-Mail-Sendmail #
# perl-MIME-tools #
# rrdtool-devel #
# libnetpbm (if image conversion from PNG to JPG is required) #
# netpbm (if image conversion from PNG to JPG is required) #
# ##################################################################### #
use Getopt::Long;
use Mail::Sendmail;
use Digest::MD5 qw(md5_hex);
use MIME::Base64;
use RRDs;
use File::Temp;
use strict;
use warnings;
use vars qw( $o_verb $o_version $o_help $o_to_group
$o_cc_recipients $o_bcc_recipients $o_addurl $inputfile $ftemp
$logo_id $graph_id $rrdfile $tmpfile $land $debugtables $tbl $var %param_vars
$hs $G $elapse $tstamp $tstart $img_get $ds );
# The version of this script
my $Version ='1.6';
my $authors = 'Frank Migge, Robert Becht';
# the sender e-mail address to be seen by recipients
my $mail_sender = "Nagios Monitoring <nagiosadmin\@yourdomain>";
# The nagios CGI URL
my $nagios_cgiurl = "http://192.168.1.1/nagios/cgi-bin";
# Modified by Robert Becht that to use PNP4Nagios links
# The PNP4Nagios URL : il not use, simply make to equal 'undef'.
my $nagios_pnpurl = "http://192.168.1.1/pnp4nagios";
my ($ra, $rb, $rc, $pnp_uri) = split('/',$nagios_pnpurl); # Otherwise you can set $pnp_uri manualy
# Here we define a simple HTML stylesheet to be used in the HTML header.
my $html_style = "body {text-align: center; font-family: Verdana, sans-serif; font-size: 10pt;}\n"
. "img.logo {float: left; margin: 10px 10px 10px; vertical-align: middle}\n"
. "span {font-family: Verdana, sans-serif; font-size: 12pt;}\n"
. "table {text-align:center; margin-left: auto; margin-right: auto;}\n"
. "th {white-space: nowrap;}\n"
. "th.even {background-color: #D9D9D9;}\n"
. "td.even {background-color: #F2F2F2;}\n"
. "th.odd {background-color: #F2F2F2;}\n"
. "td.odd {background-color: #FFFFFF;}\n"
. "th,td {font-family: Verdana, sans-serif; font-size: 10pt; text-align:left;}\n"
. "th.customer {width: 600px; background-color: #004488; color: #ffffff;}";
my $table_size = "600px";
my $header_size = "180px";
my $data_size = "420px";
my $debugtables = "</br>\n";
# ########################################################################
# SMTP related data: If the commandline argument -H/--smtphost was not
# given, we use the provided value in $o_smtphost below as the default.
# ########################################################################
my $o_smtphost = "192.168.1.64";
my $domain = "\@yourdomain";
my @listaddress = ();
# ########################################################################
# This is the logo image file, the path must point to a valid JPG, GIF or
# PNG file, i.e. the nagios logo. Best size is rectangular up to 160x80px.
# example: [nagioshome]/share/images/NagiosEnterprises-whitebg-112x46.png
# ########################################################################
my $logofile = "/usr/lib64/nagios/local/logo_devsys.png";
# ########################################################################
# Here I define the HTML color values for each Nagios notification type.
# There is one extra called TEST for sending a test e-mail from the cmdline
# outside of Nagios. The color values are used for highlighting the
# background of the notification type cell.
# ########################################################################
my %NOTIFICATIONCOLOR=('PROBLEM'=>'#FF8080','RECOVERY'=>'#80FF80','ACKNOWLEDGEMENT'=>'FFFF80',
'DOWNTIMESTART'=>'80FFFF','DOWNTIMEEND'=>'80FF80','DOWNTIMECANCELLED'=>'FFFF80',
'FLAPPINGSTART'=>'#FF8080','FLAPPINGSTOP'=>'#80FF80',' FLAPPINGDISABLED'=>'FFFF80',
'TEST'=>'80FFFF');
# ########################################################################
# Here we set the information where to pick up the RRD data files for the
# optional graph image generation, plus the graph size width x height px
# ########################################################################
my $rrd_basedir = "/var/nagios/perfdata";
my $graph_img_size = "521x60";
my $graph_bgcolor = "#F2F2F2";
my $graph_border = "#999999";
# ########################################################################
# language translated message text: $language{$land}{'A'} (=Customer)
# You can simply add here your translation...
# ########################################################################
my %language = ('en' => { 'A' => 'Customer',
'B' => 'Notification Type',
'C' => 'Service Name',
'D' => 'Service Status',
'E' => 'Service Group',
'F' => 'Service Data',
'G' => 'Hostname',
'H' => 'Hostalias',
'I' => 'IP Address',
'J' => 'Hostgroup',
'K' => 'Event Time',
'L' => 'Author',
'M' => 'Comment',
'N' => 'Nagios Monitoring System Notification',
'O' => 'Generated by Nagios, the OpenSource monitoring solution' },
'fr' => { 'A' => 'Utilisateur',
'B' => 'Type de notification',
'C' => 'Nom du service',
'D' => 'Statut du service',
'E' => 'Groupe du service',
'F' => 'Données',
'G' => 'Nom d\'hôte',
'H' => 'Alias d\'hôte',
'I' => 'Adresse IP',
'J' => 'Groupe d\'hôte',
'K' => 'Heure de la notification',
'L' => 'Auteur',
'M' => 'Commentaire',
'N' => 'Notification de la surveillance Nagios',
'O' => 'Généré par Nagios, le système de surveillance OpenSource' },
'de' => { 'A' => 'Anwender',
'B' => 'Nachrichtentyp',
'C' => 'Dienstname',
'D' => 'Dienstzustand',
'E' => 'Dienstgruppe',
'F' => 'Dienstinformationen',
'G' => 'Systemname',
'H' => 'Systemalias',
'I' => 'System IP Adresse',
'J' => 'Systemgruppe',
'K' => 'Meldungsdatum',
'L' => 'Author',
'M' => 'Kommentar',
'N' => 'Nagios Überwachungssytem Meldung',
'O' => 'Erstellt mit Nagios, dem OpenSource Überwachungssytem' },
'jp' => { 'A' => '顧客名',
'B' => '通知の種類',
'C' => 'サービス名',
'D' => 'サービスの状態',
'E' => 'サービスグループ',
'F' => 'サービスデータ出力',
'G' => 'ホスト名',
'H' => 'ホストの別名',
'I' => 'IPアドレス',
'J' => 'ホストグループ',
'K' => 'イベントの日付と時刻',
'L' => '投稿者',
'M' => 'コメント',
'N' => 'Nagios 監視システムの通知',
'O' => 'このメーセジはオープンソースの監視システムNagiosで生成されています。' });
####### Global Variables - No changes necessary below this line ##########
# Nagios notification type, i.e. PROBLEM
my $o_notificationtype = $ENV{NAGIOS_NOTIFICATIONTYPE};
# Nagios notification author (if avail.)
my $o_notificationauth = $ENV{NAGIOS_NOTIFICATIONAUTHOR};
# Nagios notification comment (if avail.)
my $o_notificationcmt = $ENV{NAGIOS_NOTIFICATIONCOMMENT};
# Nagios service description
my $o_servicedesc = $ENV{NAGIOS_SERVICEDESC};
# Nagios service state
my $o_servicestate = $ENV{NAGIOS_SERVICESTATE};
# Nagios service group the service belongs to
my $o_servicegroup = $ENV{NAGIOS_SERVICEGROUPNAME};
# Nagios monitored host name
my $o_hostname = $ENV{NAGIOS_HOSTNAME};
# Nagios monitored host alias
my $o_hostalias = $ENV{NAGIOS_HOSTALIAS};
# Nagios host group the host belongs to
my $o_hostgroup = $ENV{NAGIOS_HOSTGROUPNAME};
# Nagios monitored host IP address
my $o_hostaddress = $ENV{NAGIOS_HOSTADDRESS};
# Nagios service check output data
my $o_serviceoutput = $ENV{NAGIOS_SERVICEOUTPUT};
# Nagios date when the event was recorded
my $o_datetime = $ENV{NAGIOS_LONGDATETIME};
# The recipients defined in $CONTACTEMAIL$
my $o_to_recipients = $ENV{NAGIOS_CONTACTEMAIL};
# Modified by Robert Becht for using $CONTACTGROUPEMEMBERS$ in nagios.conf
my $o_to_group = $ENV{NAGIOS_CONTACTGROUPMEMBERS};
# The next variables are provided through args
my $o_cc_recipients = undef; # The recipients defined in $CONTACTADDRESS1$
my $o_bcc_recipients = undef; # The recipients defined in $CONTACTADDRESS2$
my $o_format = "text";# The e-mail output format (default: text)
my $o_addurl = undef; # flag to add Nagios GUI URLs to HTML e-mails
my $o_language = undef; # The e-mail output language
my $o_lang_def = "en"; # The e-mail output language default
my $o_customer = undef; # Company name and contract number for service providers
my $o_help = undef; # We want help
my $o_verb = undef; # verbose mode
my $o_version = undef; # print version
my $o_test = undef; # generate a test message
# These variables are used in various subroutines
my $text_msg = undef; # the plaintext notification
my $html_msg = undef; # the HTML-formatted notification
my $graphfile = undef; # if we generate graphs, the tmp file location
my @rrd;
my $logo_img = undef; # base64-encoded logo
my $graph_img = undef; # base64-encoded graph
my $boundary = undef; # unique string for multi-part emails
my %mail;
# ########################################################################
# subroutine defintions below
# ########################################################################
# ########################################################################
# p_version returns the program version
# ########################################################################
sub p_version { print "$0 nagios_send_service_mail.pl version : $Version\n"; }
# ########################################################################
# print_usage returns the program usage
# ########################################################################
sub print_usage {
print "Usage: $0 [-v] [-V] [-h] [-t] [-H <SMTP host>] [-p <customername>]
[-r <to_recipients> or -g <to_group>] [-c <cc_recipients>] [-b <bcc_recipients>]
[-f <text|html|multi|graph>] [-u] [-l <en|jp|fr|de|(or other languages if added)]\n";
}
# ########################################################################
# help returns the program help message
# ########################################################################
sub help {
print "\nNagios e-mail notification script for service events, version ",$Version,"\n";
print "GPL licence, (c)2010 Frank Migge\n\n";
print_usage();
print <<EOT;
This script takes over the Nagios e-mail notifications by receiving the Nagios state information,
formatting the e-mail and sending it out through an SMTP gateway.
-v, --verbose
print extra debugging information
-V, --version
prints version number
-h, --help
print this help message
-t, --test
generates a test message together with -r, --to-recipients
-H, --smtphost=HOST
name or IP address of SMTP gateway
-p, --customer="customer name and contract #"
optionally, add the customer name and contract for service providers
-r, --to-recipients
this option overrides the Nagios-provided \$CONTACTEMAIL\$ list of to: recipients
-g, --to-group-recipients \$CONTACTGROUPMEMBERS\$
this option use the list of contactgroup and reconstitutes the mail address with the hard defined \$domain
in this script. This is only possible when the contact name "abcd" works under the address "abcd\@domain".
-c, --cc-recipients
the Nagios-provided \$CONTACTADDRESS1\$ list of cc: recipients
-b, --bcc-recipients
the Nagios-provided \$CONTACTADDRESS2\$ list of bcc: recipients
-f, --format='text|html|multi|graph'
the email format to generate: either plain text,, HTML,
multipart S/MIME and multipart adding the Nagiosgraph image
-u, --addurl
this adds URL's to the Nagios web GUI for check status,
host and hostgroup views into the html mail,
requires -f html or -f multi
-l, --language='en|jp|fr|de|(or what you defined in this script)'
the prefered e-mail language. The content-type header is currently is hard-coded to UTF-8.
This might need to be changed if recipients require a different characterset encoding.
Extra: For useful debug output, go to Nagios, select a service and choose "Send custom service notification".
Entering text including the word "email-debug" in the comment field will trigger the creation of additional
tables with a list of Nagios and script variables.
EOT
}
# ########################################################################
# verb creates verbose output
# ########################################################################
sub verb {
my $t=shift;
print $t,"\n" if defined($o_verb);
}
# ########################################################################
# unique content ID are needed for multipart messages with inline logos
# ########################################################################
sub create_content_id {
my $unique_string = rand(100);
$unique_string = $unique_string . substr(md5_hex(time()),0,23);
$unique_string =~ s/(.{5})/$1\./g;
my $content_id = qq(part.${unique_string}\@) . "MAIL";
$unique_string = undef;
return $content_id;
}
# ########################################################################
# create_boundary creates the S/MIME multipart boundary strings
# ########################################################################
sub create_boundary {
my $unique_string = substr(md5_hex(time()),0,24);
$boundary = '======' . $unique_string ;
$unique_string = undef;
}
sub unknown_arg {
print_usage();
exit -1;
}
# ########################################################################
# create_address from the groupmembers list (Add by Robert Becht)
# ########################################################################
sub create_address {
chomp($o_to_group);
my @mlist = split(",",$o_to_group);
foreach (@mlist) {
my $maddress = "$_"."$domain";
# Debugging
#print "$maddress\n";
push(@listaddress,$maddress);
}
$o_to_group = join(",",@listaddress);
#Debugging
#print "$o_to_group\n";
return ($o_to_group);
}
# ########################################################################
# check_options checks and processes the commandline options given
# ########################################################################
sub check_options {
Getopt::Long::Configure ("bundling");
GetOptions(
'v' => \$o_verb, 'verbose' => \$o_verb,
'V' => \$o_version, 'version' => \$o_version,
'h' => \$o_help, 'help' => \$o_help,
't' => \$o_test, 'test' => \$o_test,
'H:s' => \$o_smtphost, 'smtphost:s' => \$o_smtphost,
'p:s' => \$o_customer, 'customer:s' => \$o_customer,
'r:s' => \$o_to_recipients, 'to-recipients:s' => \$o_to_recipients,
'g:s' => \$o_to_group, 'to-group-recipients' => \$o_to_group,
'c:s' => \$o_cc_recipients, 'cc-recipients:s' => \$o_cc_recipients,
'b:i' => \$o_bcc_recipients, 'bcc-recipients:s' => \$o_bcc_recipients,
'f:s' => \$o_format, 'format:s' => \$o_format,
'u' => \$o_addurl, 'addurl' => \$o_addurl,
'l:s' => \$o_language, 'language:s' => \$o_language
) or unknown_arg();
# Basic checks
if (defined ($o_help)) { help(); exit 0};
if (defined($o_version)) { p_version(); exit 0};
if ((! defined($o_to_recipients)) && (! defined($o_to_group))) { # no recipients provided
print "Error: no recipients have been provided\n"; print_usage(); exit -1}
else {
if (! defined($o_to_group)) {
%mail = ( To => $o_to_recipients,
From => $mail_sender,
Sender => $mail_sender ); }
else { &create_address;
%mail = ( To => $o_to_group,
From => $mail_sender,
Sender => $mail_sender ); }
}
if ( $o_format ne "text" && $o_format ne "html"
&& $o_format ne "multi" && $o_format ne "graph") # wrong mail format
{ print "Error: wrong e-mail format.\n"; print_usage(); exit -1}
if (defined($o_addurl) && $o_format eq "text")
{ print "Error: cannot add URL's to text.\n"; print_usage(); exit -1}
if (defined($o_test)) { create_test_data(); };
# Modified by Robert Becht to support additional languages
# if no language has been requested, try to determine default from OS
if (! defined($o_language)) {
# if environment $LANG is set, try to extract the first two country chars, i.e. "en|de|fr"
if ($ENV{LANG} eq "C" || $ENV{LANG} eq "POSIX") { $land = "en"; }
else { ($land, my $rem) = split('_',$ENV{LANG}, 2); }
} else { $land = $o_language; }
# Last resort: Set "English" if the requested language is not supported by our script
if (! $language{$land}{'A'}) { $land = $o_lang_def; }
}
# ########################################################################
# if -t or --test, we need to create sample test data to send out
# In order to successfully test a e-mail with performance graph generation
# set a valid hostname and servicedesc to be able to pick up a RRD file.
# ########################################################################
sub create_test_data {
if (! defined($o_customer)){ $o_customer = "ACME Corporation";}
if (! defined($o_notificationtype)){ $o_notificationtype = "TEST";}
if (! defined($o_servicestate)){ $o_servicestate = "UNKNOWN";}
if (! defined($o_hostname)){ $o_hostname = "susie114";}
if (! defined($o_hostalias)){ $o_hostalias = "susie114.frank4dd.com (LINUX)";}
if (! defined($o_hostaddress)){ $o_hostaddress = "127.0.0.1";}
if (! defined($o_hostgroup)){ $o_hostgroup = "Linux Servers";}
if (! defined($o_servicedesc)){ $o_servicedesc = "os_cpu_load";}
if (! defined($o_servicegroup)){ $o_servicegroup = "performance checks";}
if (! defined($o_datetime)){ $o_datetime = `date`;}
# if (! defined($o_datetime)) {$o_datetime = localtime time;}
if (! defined($o_serviceoutput)){ $o_serviceoutput = "Test output for this service";}
if (! defined($o_notificationauth)){ $o_notificationauth = "John Doe";}
# Setting the keyword "email-debug" in the notification comment below triggers the creation of debug tables
if (! defined($o_notificationcmt)){ $o_notificationcmt = "Test message for the service with email-debug";}
}
# ########################################################################
# Create a plaintext message -> $text_msg
# ########################################################################
sub create_message_text {
$text_msg = $language{$land}{'N'}."\n"
. "=====================================\n\n";
# if customer name was given for service providers, display it here
if ( defined($o_customer)) {
$text_msg = $text_msg . $language{$land}{'A'} . ": $o_customer\n";
}
$text_msg = $text_msg
. $language{$land}{'B'} . ": $o_notificationtype\n"
. $language{$land}{'C'} . ": $o_servicedesc\n"
. $language{$land}{'D'} . ": $o_servicestate\n"
. $language{$land}{'E'} . ": $o_servicegroup\n"
. $language{$land}{'F'} . ": $o_serviceoutput\n\n"
. $language{$land}{'G'} . ": $o_hostname\n"
. $language{$land}{'H'} . ": $o_hostalias\n"
. $language{$land}{'I'} . ": $o_hostaddress\n"
. $language{$land}{'J'} . ": $o_hostgroup\n"
. $language{$land}{'K'} . ": $o_datetime\n\n";
# if author and comment data has been passed from nagios
# and these variables have content, then we add two more columns
if ( ( defined($o_notificationauth) && defined($o_notificationcmt) ) &&
( ($o_notificationauth ne "") && ($o_notificationcmt ne "") ) ) {
$text_msg = $text_msg . $language{$land}{'L'} . ": $o_notificationauth\n"
. $language{$land}{'M'} . ": $o_notificationcmt\n\n";
}
$text_msg = $text_msg . "-------------------------------------\n"
. $language{$land}{'O'} . ".\n" . "(". $authors . ")\n" ;
}
# ########################################################################
# Create a simple HTML message -> $html_msg
# ########################################################################
sub create_message_html {
# Start HTML message definition
$html_msg = "<html><head><style type=\"text/css\">$html_style</style></head><body>\n"
. "<table width=$table_size><tr>\n";
if ($o_format eq "multi" || $o_format eq "graph") {
$logo_id = create_content_id();
$html_msg = $html_msg . "<td><img class=\"logo\" src=\"cid:$logo_id\"></td>"
. "<td><span>$language{$land}{'N'}</span></td></tr><tr>\n";
} else {
$html_msg = $html_msg
. "<th colspan=2><span>$language{$land}{'N'}</span></th></tr><tr>\n"; }
if ( defined($o_customer)) {
$html_msg = $html_msg
. "<th colspan=2 class=customer>$o_customer</th></tr><tr>\n"; }
$html_msg = $html_msg
. "<th width=$header_size class=even>$language{$land}{'B'}:</th>\n"
. "<td bgcolor=$NOTIFICATIONCOLOR{$o_notificationtype}>\n"
. "$o_notificationtype</td></tr>\n"
. "<tr><th class=odd>$language{$land}{'C'}:</th><td>$o_servicedesc</td></tr>\n"
. "<tr><th class=even>$language{$land}{'E'}:</th><td class=even>\n";
# The Servicegroup URL http://<nagios-web>/cgi-bin/status.cgi?servicegroup=$SERVICEGROUPNAME$&style=overview
# This URL shows the service group table listing ofthe hosts that have this service
if (defined($o_addurl)) {
$html_msg = $html_msg
. "<a href=\"$nagios_cgiurl/status.cgi?servicegroup=$o_servicegroup&style=overview\">$o_servicegroup</a>";
} else { $html_msg = $html_msg . $o_servicegroup; }
$html_msg = $html_msg . "</td></tr>\n"
. "<tr><th class=odd>$language{$land}{'D'}:</th><td>$o_servicestate</td></tr>\n"
. "<tr><th class=even>$language{$land}{'F'}:</th><td class=even>\n";
# The ServiceOutput URL http://<nagios-web>/cgi-bin/extinfo.cgi?type=2&host=$HOSTNAME$&service=$SERVICEDESC$
# This URL shows the full service details and commands for service management (ack, re-check, disable, etc)
if (defined($o_addurl)) {
if ( $nagios_pnpurl eq '') {
$html_msg .= "<a href=\"$nagios_cgiurl/extinfo.cgi?type=2&host=$o_hostname&service=$o_servicedesc\">$o_serviceoutput</a>\n";
} else {
# Modified by Robert Becht for link to PNP4Nagios graph
$html_msg .= "<a href=\"$nagios_pnpurl/index.php/graph?host=$o_hostname&srv=$o_servicedesc\">$o_serviceoutput</a>\n"; }
} else{ $html_msg .= $o_serviceoutput; }
$html_msg = $html_msg . "</td></tr>\n"
. "<tr><th class=odd>$language{$land}{'G'}:</th><td>\n";
# The Hostname URL http://<nagios-web>/cgi-bin/status.cgi?host=$HOSTNAME$&style=detail
# this URL shows the host and all services underneath it
if (defined($o_addurl)) {
$html_msg = $html_msg
. "<a href=\"$nagios_cgiurl/status.cgi?host=$o_hostname&style=detail\">$o_hostname</a>";
} else { $html_msg = $html_msg . $o_hostname; }
$html_msg = $html_msg . "</td></tr>\n"
. "<tr><th class=even>$language{$land}{'H'}:</th><td class=even>$o_hostalias</td></tr>\n"
. "<tr><th class=odd>$language{$land}{'I'}:</th><td>$o_hostaddress</td></tr>\n"
. "<tr><th class=even>$language{$land}{'J'}:</th><td class=even>\n";
# The Hostgroup URL http://<nagios-web>/cgi-bin/status.cgi?hostgroup=$HOSTGROUPNAME$&style=overview
# This URL shows the hostgroup table listing for all individual hosts that belong to it
if (defined($o_addurl)) {
$html_msg = $html_msg
. "<a href=\"$nagios_cgiurl/status.cgi?hostgroup=$o_hostgroup&style=overview\">$o_hostgroup</a>";
} else { $html_msg = $html_msg . $o_hostgroup; }
$html_msg = $html_msg . "</td></tr>\n"
. "<tr><th class=odd>$language{$land}{'K'}:</th><td>$o_datetime</td></tr>\n";
# If the author and comment data has been passed from nagios
# and these variables have content, then we add two more columns
if ( ( defined($o_notificationauth) && defined($o_notificationcmt) ) &&
( ($o_notificationauth ne "") && ($o_notificationcmt ne "") ) ) {
$html_msg = $html_msg . "<tr><th class=even>$language{$land}{'L'}:</th>\n"
. "<td class=even>$o_notificationauth</td></tr>\n"
. "<tr><th class=odd>$language{$land}{'M'}:</th>\n"
. "<td>$o_notificationcmt</td></tr>\n";
}
$html_msg = $html_msg . "</table></br>\n";
# if we got the graph format and a image has been generated, we add it here
if (defined($graph_img) && $o_format eq "graph") {
$graph_id = create_content_id();
$html_msg = $html_msg . "<img src=\"cid:$graph_id\">\n";
}
# add the Nagios footer tag line here
$html_msg = $html_msg . "</br><hr>\n$language{$land}{'O'}\n
.</br><em><font size=\"-1\" >(Authors:$authors)</font></em><hr>\n";
# add the extra debugtables if verbose output had been requested,
# or if the notification command contains the keyword "email-debug"
if (defined($o_notificationcmt) && ($o_notificationcmt =~ m/email-debug/i)
|| defined($o_verb)) {
&create_debugtable;
$html_msg = $html_msg . $debugtables;
}
# End HTML message definition
$html_msg = $html_msg . "</body></html>\n";
}
# #######################################################################
# urlencode() URL encode a string
# #######################################################################
sub urlencode {
$_[0] =~ s/([\W])/"%" . uc(sprintf("%2.2x",ord($1)))/eg;
return $_[0];
}
# #######################################################################
# hashcolor() Choose a color for service
# #######################################################################
sub hashcolor {
my $c=0;
map{$c=(51*$c+ord)%(216)}split//,"$_[0]x";
my $i = 0;
my $n = 0;
my $m = 0;
my @h=(51*int $c/36,51*int $c/6%6,51*($c%6));
for$i(0..2){$m=$i if$h[$i]<$h[$m];$n=$i if$h[$i]>$h[$n]}
$h[$m]=102if$h[$m]>102;$h[$n]=153if$h[$n]<153;
$c=sprintf"%06X",$h[2]+$h[1]*256+$h[0]*16**4;
return $c;
}
# #######################################################################
# dbfilelist() Get list of matching rrd files
# #######################################################################
sub dbfilelist {
my($host,$service, $rrddir) = @_;
my $hs;
# New style, files inside a <hostname> directory
$rrddir .= "/" . $host;
$hs = urlencode "$service" . "___";
verb("sub dbfilelist: Checking files inside directory: ".$rrddir);
my @rrd;
opendir DH, $rrddir or verb("sub dbfilelist: Cannot open: ".$rrddir);
@rrd = grep s/^${hs}(.+)\.rrd$/$1/, readdir DH;
closedir DH;
verb("sub dbfilelist: We found number of RRD files: ".@rrd);
return @rrd;
}
# #######################################################################
# graphinfo() Find graphs and values
# #######################################################################
sub graphinfo {
my($host,$service,$rrddir) = @_;
my(@rrd,$ds,$f,$dsout,@values,$hs,%H,%R);
$hs = $host . "/";
$hs .= urlencode "$service" . "___";
# Determine which files to read lines from
@rrd = map {{ file=>$_ }}
map { "${hs}${_}.rrd" }
dbfilelist($host,$service, $rrddir);
# we stop processing here if we could not find a file
if (@rrd < 1) {
verb("sub graphinfo: Could not find any graph file.");
return undef;
} else {
verb("sub graphinfo: Listing $hs db files in $rrddir: "
. join ', ', map { $_->{file} } @rrd);
}
$rrdfile = $rrd[0]->{file};
$ds = RRDs::info "$rrddir/$rrdfile";
verb("sub graphinfo: RRDs::info ERR " . RRDs::error) if RRDs::error;
map { $rrd[0]->{line}{$_} = 1}
grep {!$H{$_}++}
map { /ds\[(.*)\]/; $1 }
grep /ds\[(.*)\]/,
keys %$ds;
verb("sub graphinfo: Found datasources: " . %$ds);
return \@rrd;
}
# #######################################################################
# rrdline() Generate the rrd parameters to produce a graph
# #######################################################################
sub rrdline {
my($host,$service,$geom,$G,$rrddir,$tmpfile) = @_;
my($g,$f,$v,$c,@ds);
my $directory = $rrddir;
@ds = ($tmpfile, '-a', 'PNG', '-t', $service);
push @ds, "--color=BACK$graph_bgcolor",
"--color=SHADEA$graph_border",
"--color=SHADEB$graph_border";
# Identify where to pull data from and what to call it
for $g ( @$G ) {
$f = $g->{file};
verb("sub rrdline: set filename: $f");
# Compute the longest label length
my $longest = (sort map(length,keys(%{ $g->{line} })))[-1];
for $v ( sort keys %{ $g->{line} } ) {
$c = hashcolor($v);
verb("sub rrdline: file=$f line=$v color=$c");
my $sv = "$v";
my $label = sprintf("%-${longest}s", $sv);
push @ds , "DEF:$sv=$directory/$f:$v:AVERAGE"
, "LINE2:${sv}#$c:$label";
my $format = '%6.2lf%s';
# Graph labels
push @ds, "GPRINT:$sv:MAX:Max\\: $format"
, "GPRINT:$sv:AVERAGE:Avg\\: $format"
, "GPRINT:$sv:MIN:Min\\: $format"
, "GPRINT:$sv:LAST:Cur\\: ${format}\\n";
}
}
# Dimensions of graph if geom is specified
if ( $geom ) {
my($w,$h) = split 'x', $geom;
push @ds, '-w', $w, '-h', $h;
}
return @ds;
}
# ########################################################################
# uuencode_image(filename) converts a existing binary source image file
# into a base64-image string.
# ########################################################################
sub uuencode_img {
my($inputfile) = @_;
open (IMG, $inputfile) or verb("uuencode_img: Cannot read source image file: $inputfile - $!");
binmode IMG; undef $/;
my $uuencoded_img = encode_base64(<IMG>);
close IMG;
verb("uuencode_img: completed conversion of source image file: $inputfile - $!");
return $uuencoded_img;
}
# #######################################################################
# create_graph_img() tries to create a performance graph image file (PNG)
# Input is the hostname and servicename, then we try to find a matching
# RRD file according to NagiosGraph's filesystem layout. If there is one,
# it queries the RRD information and graphs the last 24 hours similar to
# Nagiosgraph.
# #######################################################################
sub create_graph_img {
my $fhandle = undef;
my $graph_img = undef;
# Figure out db files and line labels
my $G = graphinfo($o_hostname,$o_servicedesc,$rrd_basedir);
# if we could not find RRD data, we return $img as undef
if(! defined($G)) {
verb("sub create_graph_img: No graph data for $o_hostname,$o_servicedesc was found.");
return $graph_img;
}
# generate temporary graph files for todays RRD data
$fhandle = File::Temp->new() or verb("create_graph_img: Cannot create temporary image file.");
my $tmpfile = $fhandle->filename;
$ftemp = $tmpfile;
my @ds = rrdline($o_hostname,$o_servicedesc,$graph_img_size,$G,$rrd_basedir,$tmpfile);
verb("sub create_graph_img: RRDs::graph ". join ' ', @ds);
RRDs::graph(@ds);
verb("sub create_graph_img: RRDs::graph ERR " . RRDs::error) if RRDs::error;
# because our mail system being Lotus Notes, which is not supporting PNG
# images, we must convert them from PNG to JPG before we can continue.
# comment out the next 3 lines if PNG images work with your mail clients
# my $jpg_tmpfile = $tmpfile.".jpg";
# `pngtopnm $tmpfile | pnmtojpeg >$jpg_tmpfile`;
# `mv $jpg_tmpfile $tmpfile`;
# In e-mails, images need to be base64 encoded, we uuencode here
$graph_img = uuencode_img($tmpfile);
return $graph_img;
}
# ########################################################################
# Added by Robert Becht for request an PNP4Nagios graph
# ########################################################################
sub import_pnp_graph {
use LWP::Simple;
$elapse = (1 * 3600); # This set 1 hour history
$tstamp = time();
$tstart = ($tstamp - $tstamp);
$img_get = "http://127.0.0.1/$pnp_uri/image?host=$o_hostname&srv=$o_servicedesc&source=0&start=$tstart&end=$tstamp";
# generate temporary graph files for todays RRD data
my $fhandle = File::Temp->new( UNLINK =>1, SUFFIX => '.png') or verb("create_graph_img: Cannot create temporary image file.");
my $tmpfile = $fhandle->filename;
$ftemp = $tmpfile;
# write the graphik file in $tmpfile
print $fhandle get("$img_get");
# This is for graph size
my $pnmfile = `pngtopnm $tmpfile`;
(my $xysize = $graph_img_size) =~ s/x/ /;
`pamscale -xysize $xysize $pnmfile | pnmtopng >$img_get`; # or use pnmtojpeg if png not supported ...
$graph_img = uuencode_img($tmpfile);
return $graph_img;
}
# ########################################################################
# language translated email subject: $lang{$land}
# ########################################################################
sub set_subject {
my $subject;
my %lang = ('en' => "Nagios: $o_notificationtype service $o_servicedesc on $o_hostname ($o_hostgroup) is $o_servicestate",
'de' => "Nagios: $o_notificationtype $o_hostname($o_hostgroup) mit Dienst $o_servicedesc ist $o_servicestate",
'jp' => "Nagios: $o_notificationtype $o_hostname($o_hostgroup)のサービス $o_servicedesc $o_servicestate",
'fr' => "Nagios: $o_notificationtype : le service $o_servicedesc sur $o_hostname ($o_hostgroup) est $o_servicestate" );
if (!defined($lang{$land})) { $subject = $lang{'en'}; }
else { $subject = $lang{$land}; }
return $subject;
}
# #######################################################################
# main
# #######################################################################
check_options();
$mail{Cc} = $o_cc_recipients if ($o_cc_recipients);
$mail{Bcc} = $o_bcc_recipients if ($o_bcc_recipients);
$mail{smtp} = $o_smtphost;
$mail{subject} = set_subject();
# If the mail server requires authentication, try this line:
# $mail{auth} = {user => "<username>", password => "<mailpw>", method="">"LOGIN PLAIN", required=>1};
if ($o_format eq "graph") {
if ( ! defined $pnp_uri) {
verb("main: trying to create the a graph image.");
$graph_img = create_graph_img();
} else { $graph_img = import_pnp_graph();}
}
if ($o_format eq "multi" || $o_format eq "graph") {
verb("main: Sending HTML email (language: $land) with inline logo.");
# In e-mails, images need to be base64 encoded, we uuencode here
my $logo_img = uuencode_img($logofile);
create_boundary();
create_message_html();
$mail{'content-type'} = qq(multipart/related; boundary="$boundary");
$boundary = '--' . $boundary;
# Here we define the mail content to be send
my $mail_content = "This is a multi-part message in MIME format.\n"
# create the first boundary start marker for the main message
. "$boundary\n"
. "Content-Type: text/html; charset=utf-8\n"
. "Content-Transfer-Encoding: 8bit\n\n"
. "$html_msg\n";
# create the second boundary marker for the logo
$mail_content = $mail_content . "$boundary\n"
. "Content-Type: image/gif; name=\"logo.gif\"\n"
. "Content-Transfer-Encoding: base64\n"
. "Content-ID: <$logo_id>\n"
. "Content-Disposition: inline; filename=\"logo.gif\"\n\n"
. "$logo_img\n";
# if we got the graph format and a image has been generated, we add it here
# create the third boundary marker for the graph
if (defined($graph_img) && $o_format eq "graph") {
$mail_content = $mail_content . "\n"
. "$boundary\n"
. "Content-Type: image/jpg; name=\"graph.jpg\"\n"
. "Content-Transfer-Encoding: base64\n"
. "Content-ID: <$graph_id>\n"
. "Content-Disposition: inline; filename=\"graph.jpg\"\n\n"
. "$graph_img\n";
}
# create the final end boundary marker
$mail_content = $mail_content . $boundary . "--\n";
# put the completed message body into the mail
$mail{body} = $mail_content ;
}
elsif ($o_format eq "html") {
create_message_html();
$mail{'content-type'} = qq(text/html; charset="utf-8");
$mail{body} = $html_msg ;
} else {
create_message_text();
$mail{'content-type'} = qq(text/plain; charset="utf-8");
$mail{body} = $text_msg ;
}
sendmail(%mail) or die $Mail::Sendmail::error;
verb("Sendmail Log says:\n$Mail::Sendmail::log\n");
exit 0;
# #######################################################################
# Create a debugging table to check on Nagios and script variables
# Added by Robert Becht to create a HTML table for debugging
# #######################################################################
sub create_debugtable() {
my $varcount = 0;
my $oddcheck = "odd";
# Check if the following variables are defined
my %param_vars = (
'script' => { "title" => 'Script debug data',
"o_verb" => \$o_verb,
"o_version" => \$o_version,
"o_help" => \$o_help,
"o_smtphost" => \$o_smtphost,
"o_customer" => \$o_customer,
"o_to_recipients" => \$o_to_recipients,
"o_to_group" => \$o_to_group,
"o_cc_recipients" => \$o_cc_recipients,
"o_bcc_recipients" => \$o_bcc_recipients,
"o_format" => \$o_format,
"o_addurl" => \$o_addurl,
"o_language" => \$o_language,
"o_test" => \$o_test,
"o_smtphost" => \$o_smtphost,
"domain" => \$domain,
"land" => \$land,
"logo file" => \$logofile,
"temporary file" => \$ftemp,
"boundary" => \$boundary },
'nagios' => { "title" => 'Nagios debug data',
"o_notificationtype" => \$o_notificationtype,
"o_notificationauth" => \$o_notificationauth,
"o_notificationcmt" => \$o_notificationcmt,
"o_servicedesc" => \$o_servicedesc,
"o_servicestate" => \$o_servicestate,
"o_servicegroup" => \$o_servicegroup,
"o_hostname" => \$o_hostname,
"o_hostalias" => \$o_hostalias,
"o_hostgroup" => \$o_hostgroup,
"o_hostaddress" => \$o_hostaddress,
"o_serviceoutput" => \$o_serviceoutput,
"o_datetime" => \$o_datetime,
"o_to_recipients" => \$o_to_recipients,
"o_to_group" => \$o_to_group },
'rrdbase' => { "title" => 'RRD debug data',
"rrd_basedir" => \$rrd_basedir,
"rrdfile" => \$rrdfile,
"hs" => \$hs,
"rrdfile" => \$rrdfile,
"DS" => \$ds,
"labels" => \$G },
'pnp' => { "title" => 'PNP debug data',
"PNP url" => \$nagios_pnpurl,
"PNP uri" => \$pnp_uri,
"img_get" => \$img_get,
"interval(s)" => \$elapse,
"time start" => \$tstamp } );
# display the script variables
# Tables loop
foreach $tbl (keys %param_vars) {
$debugtables .= "</br>\n"
. "<table width=$table_size>\n"
. "<tr><th colspan=2 class=customer>$param_vars{$tbl}->{'title'}</th></tr>\n";
$varcount = 0;
# Data loop
foreach $var (keys %{$param_vars{$tbl}}) {
if ($var ne 'title') {
if ($varcount%2) {$oddcheck = "odd";
} else {$oddcheck = "even";}
$debugtables .= "<tr><th class=$oddcheck>$var</th>";
if ((! defined(${$param_vars{$tbl}->{$var}})) || (${$param_vars{$tbl}->{$var}} eq '')) {
$debugtables .= "<td class=$oddcheck> </td></tr>\n";
} else {
$debugtables .= "<td class=$oddcheck>${$param_vars{$tbl}->{$var}}</td></tr>\n";
# # Debugging
# print $var . "= " . ${$param_vars{$tbl}->{$var}} . "\n";
}
$varcount++;
}
}
$debugtables .= "</table>";
$debugtables .="</br>\n";
}
}
A parte do script que é responsável por montar os endereços de email é essa:
# Basic checks
if (defined ($o_help)) { help(); exit 0};
if (defined($o_version)) { p_version(); exit 0};
if ((! defined($o_to_recipients)) && (! defined($o_to_group))) { # no recipients provided
print "Error: no recipients have been provided\n"; print_usage(); exit -1}
else {
if (! defined($o_to_group)) {
%mail = ( To => $o_to_recipients,
From => $mail_sender,
Sender => $mail_sender ); }
else { &create_address;
%mail = ( To => $o_to_group,
From => $mail_sender,
Sender => $mail_sender ); }
}
Porém ela é a mesma nos dois scripts, porém funciona apenas em um.
Pergunta
joao_vitorino
Eu tenho script acima para enviar e-mails personalizados em HTML com alertas do Nagios referentes a hosts. Esse script funciona normalmente. Envia um email para cada contato do nagios.
Porém o script abaixo - com a mesma funcionalidade porém para enviar emails de alertas de serviços do Nagios - não funciona como deveria. Ele enviar mais de um email - dependendo da quantidade de contatos - Ex: Preciso enviar o alerta do nagios para 4 emails, então ele envia o alerta para cada um dos contatos 4 vezes, outro problema é que ele ao invês de pegar o endereço de email de cada contato, ele pega o nome do contato e adiciona o sufixo @domain.com, ou seja, um usuário que o contato no nagios é joaojunior porém o email é joao@domain.com, o script acaba enviando email para joaojunior@domain.com. O script com problema está abaixo.
A parte do script que é responsável por montar os endereços de email é essa:
Porém ela é a mesma nos dois scripts, porém funciona apenas em um.
Link para o comentário
Compartilhar em outros sites
0 respostass a esta questão
Posts Recomendados
Participe da discussão
Você pode postar agora e se registrar depois. Se você já tem uma conta, acesse agora para postar com sua conta.