summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel Filion <lelutin@gmail.com>2010-12-14 15:14:54 -0500
committerGabriel Filion <lelutin@gmail.com>2010-12-21 15:38:16 -0500
commit7c9f6d224d9bf66bc1c69b1baa066f98b9302999 (patch)
tree1da169bde639d82b4cd5c8c98c4f81468f68b563
parent5d5ec8c28d0fe39359af8db159b14faeae397e1f (diff)
Add nagios IRC bot
Koumbit is using an IRC bot that Micah provided. It is a pair of perl scripts that send Nagios notifications as messages in an IRC channel. Add a class to make installing this IRC bot easy. It also defines commands 'notify-by-irc' and 'host-notify-by-irc' that can be used with checks to send notifications via the bot. Signed-off-by: Gabriel Filion <lelutin@gmail.com>
-rw-r--r--README34
-rw-r--r--files/irc_bot/riseup-nagios-client.pl40
-rw-r--r--files/irc_bot/riseup-nagios-server.pl157
-rw-r--r--manifests/irc_bot.pp71
-rw-r--r--templates/irc_bot/nagios-nsa.sh.erb71
-rw-r--r--templates/irc_bot/nsa.cfg.erb13
6 files changed, 386 insertions, 0 deletions
diff --git a/README b/README
index cdcb5d3..aa33592 100644
--- a/README
+++ b/README
@@ -60,6 +60,17 @@ Obviously, the check command must either be defined using nagios_command objects
files directly.
+IRC bot
+-------
+
+Notifications can easily be sent to an IRC channel by using a bot. To do so,
+simply include 'nagios::irc_bot' on the nagios server and define the right
+$nagios_nsa_* variables (see the 'Variables' section below).
+
+You can then use the notification commands 'notify-by-irc' and
+'host-notify-by-irc' with service and host definitions to make them report
+state changes over IRC.
+
Caveats
=======
@@ -102,6 +113,29 @@ Options to change the behavior of the nagios module:
may also need to flip "check_external_commands" in
"nagios.cfg" to enable this functionality.
+- nagios_nsa_socket: This optional variable can be used to specify the path to
+ the socket file that the IRC daemon should use.
+
+- nagios_nsa_server: When using the IRC bot, this defines the server address of
+ the IRC network on which the bot will connect.
+
+- nagios_nsa_port: Defines the port number on the IRC server on which the bot
+ should connect. When this variable is not set, the port used
+ by default is 6667.
+
+- nagios_nsa_nickname: This is the nickname that the IRC bot will take.
+
+- nagios_nsa_password: Some networks require a password to connect to them.
+ This defines such a password.
+
+- nagios_nsa_channel: The name of the channel that the IRC bot will join and
+ will post notifications to.
+
+- nagios_nsa_pidfile: This optional variable can be used to define the path to
+ the file that will contain the process ID of the IRC bot
+ daemon.
+- nagios_nsa_realname: The IRC bot user's real name that will be displayed. By
+ default, the real name is 'Nagios'.
Examples
========
diff --git a/files/irc_bot/riseup-nagios-client.pl b/files/irc_bot/riseup-nagios-client.pl
new file mode 100644
index 0000000..fd28996
--- /dev/null
+++ b/files/irc_bot/riseup-nagios-client.pl
@@ -0,0 +1,40 @@
+#!/usr/bin/perl -w
+
+# ##############################################################################
+# Infrabot-Client - a simple Infrabot client which sends it's whole command
+# line arguments to a local UNIX domain socket.
+# ##############################################################################
+
+use strict;
+use IO::Socket;
+
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+# >> CONFIGURATION >>
+
+my $SOCKET = '/var/run/nagios/nsa.socket';
+
+# << CONFIGURATION <<
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+if (@ARGV == 0) {
+ print "Hey - specify a message, sucker!\n";
+ exit(1);
+}
+
+unless (-S $SOCKET) {
+ die "Socket '$SOCKET' doesn't exist or isn't a socket!\n";
+}
+
+unless (-r $SOCKET) {
+ die "Socket '$SOCKET' can't be read!\n";
+}
+
+my $sock = IO::Socket::UNIX->new (
+ Peer => $SOCKET,
+ Type => SOCK_DGRAM,
+ Timeout => 10
+) || die "Can't open socket '$SOCKET'!\n";
+
+print $sock "@ARGV";
+close($sock);
diff --git a/files/irc_bot/riseup-nagios-server.pl b/files/irc_bot/riseup-nagios-server.pl
new file mode 100644
index 0000000..7880dde
--- /dev/null
+++ b/files/irc_bot/riseup-nagios-server.pl
@@ -0,0 +1,157 @@
+#!/usr/bin/perl -w
+
+# ##############################################################################
+# a simple IRC bot which dispatches messages received via local domain sockets
+# ##############################################################################
+
+use strict;
+use File::Basename;
+
+BEGIN {
+ unshift @INC, dirname($0);
+}
+
+my $VERSION = '0.2';
+my $running = 1;
+
+# Read a configuration file
+# The arg can be a relative or full path, or
+# it can be a file located somewhere in @INC.
+sub ReadCfg
+{
+ my $file = $_[0];
+
+ our $err;
+
+ { # Put config data into a separate namespace
+ package CFG;
+
+ # Process the contents of the config file
+ my $rc = do($file);
+
+ # Check for errors
+ if ($@) {
+ $::err = "ERROR: Failure compiling '$file' - $@";
+ } elsif (! defined($rc)) {
+ $::err = "ERROR: Failure reading '$file' - $!";
+ } elsif (! $rc) {
+ $::err = "ERROR: Failure processing '$file'";
+ }
+ }
+
+ return ($err);
+}
+
+# Get our configuration information
+if (my $err = ReadCfg('/etc/nagios_nsa.cfg')) {
+ print(STDERR $err, "\n");
+ exit(1);
+}
+
+use POSIX qw(setsid);
+use IO::Socket;
+use Net::IRC;
+
+sub new {
+ my $self = {
+ socket => undef,
+ irc => undef,
+ conn => undef
+ };
+
+ return bless($self, __PACKAGE__);
+}
+
+sub daemonize {
+ my $self = shift;
+ my $pid;
+
+ chdir '/' or die "Can't chdir to /: $!";
+
+ open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
+ open STDOUT, '>/dev/null' or die "Can't write to /dev/null: $!";
+
+ defined ($pid = fork) or die "Can't fork: $!";
+
+ if ($pid && $CFG::Nsa{'pidfile'}) { # write pid of child
+ open PID, ">$CFG::Nsa{'pidfile'}" or die "Can't open pid file: $!";
+ print PID $pid;
+ close PID;
+ }
+ exit if $pid;
+ setsid or die "Can't start a new session: $!";
+
+ #open STDERR, '>&STDOUT' or die "Can't dup stdout: $!";
+}
+
+sub run {
+ my $self = shift;
+
+ $self->{irc}->do_one_loop();
+}
+
+sub shutdown {
+ my $sig = shift;
+
+ print STDERR "Received SIG$sig, shutting down...\n";
+ $running = 0;
+}
+
+sub socket_has_data {
+ my $self = shift;
+
+ $self->{socket}->recv(my $data, 1024);
+ $self->{conn}->privmsg($CFG::Nsa{'channel'}, $data);
+}
+
+sub irc_on_connect {
+ my $self = shift;
+
+ print STDERR "Joining channel '$CFG::Nsa{'channel'}'...\n";
+ $self->join($CFG::Nsa{'channel'});
+}
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+my $bot = &new;
+
+if (-e $CFG::Nsa{'socket'}) {
+ die "Socket '$CFG::Nsa{'socket'}' exists!\n";
+}
+
+$bot->{socket} = IO::Socket::UNIX->new (
+ Local => $CFG::Nsa{'socket'},
+ Type => SOCK_DGRAM,
+ Listen => 5
+) || die "Can't create socket '$CFG::Nsa{'socket'}'!\n";
+
+$SIG{INT} = $SIG{TERM} = \&shutdown;
+
+$bot->daemonize();
+$bot->{irc} = new Net::IRC;
+
+$bot->{conn} = $bot->{irc}->newconn (
+ Server => $CFG::Nsa{'server'},
+ Port => $CFG::Nsa{'port'},
+ Nick => $CFG::Nsa{'nickname'},
+ Username => $CFG::Nsa{'nickname'},
+ Password => $CFG::Nsa{'password'},
+ Ircname => $CFG::Nsa{'realname'} . " (NSA $VERSION)",
+) || die "Can't connect to server '$CFG::Nsa{'server'}'!\n";
+
+$bot->{conn}->add_global_handler(376, \&irc_on_connect);
+$bot->{conn}->add_global_handler('nomotd', \&irc_on_connect);
+$bot->{irc}->addfh($bot->{socket}, \&socket_has_data, 'r', $bot);
+
+while ($running) {
+ $bot->run();
+}
+
+close($bot->{socket});
+unlink($CFG::Nsa{'socket'});
+
+exit(0);
+
+1;
+
+__END__
diff --git a/manifests/irc_bot.pp b/manifests/irc_bot.pp
new file mode 100644
index 0000000..4092e67
--- /dev/null
+++ b/manifests/irc_bot.pp
@@ -0,0 +1,71 @@
+class nagios::irc_bot {
+ if ( ! ($nagios_nsa_server and $nagios_nsa_nickname and $nagios_nsa_channel) ) {
+ fail("Please provide values at least for \$nagios_nsa_server, \$nagios_nsa_nickname and \$nagios_nsa_channel")
+ }
+
+ $nagios_nsa_socket = $nagios_nsa_socket ? {
+ '' => '/var/run/nagios3/nsa.socket',
+ default => $nagios_nsa_socket,
+ }
+ $nagios_nsa_pidfile = $nagios_nsa_pidfile ? {
+ '' => '/var/run/nagios3/nsa.pid',
+ default => $nagios_nsa_pidfile,
+ }
+ $nagios_nsa_port = $nagios_nsa_port ? {
+ '' => '6667',
+ default => $nagios_nsa_port,
+ }
+ $nagios_nsa_realname = $nagios_nsa_realname ? {
+ '' => 'Nagios',
+ default => $nagios_nsa_realname,
+ }
+
+ if (! $nagios_nsa_password) {
+ $nagios_nsa_password = ''
+ }
+
+ file { "/usr/local/bin/riseup-nagios-client.pl":
+ owner => root, group => root, mode => 0755,
+ source => "puppet:///modules/nagios/irc_bot/riseup-nagios-client.pl",
+ }
+ file { "/usr/local/bin/riseup-nagios-server.pl":
+ owner => root, group => root, mode => 0755,
+ source => "puppet:///modules/nagios/irc_bot/riseup-nagios-server.pl",
+ }
+ file { "/etc/init.d/nagios-nsa":
+ owner => root, group => root, mode => 0755,
+ content => template('nagios/irc_bot/nagios-nsa.sh.erb'),
+ require => File["/usr/local/bin/riseup-nagios-server.pl"],
+ }
+ file { "/etc/nagios_nsa.cfg":
+ ensure => present,
+ owner => nagios, group => root, mode => 0400,
+ content => template('nagios/irc_bot/nsa.cfg.erb'),
+ }
+
+ package { "libnet-irc-perl":
+ ensure => present,
+ }
+
+ exec { "nagios_nsa_init_script":
+ command => "/usr/sbin/update-rc.d nagios-nsa defaults",
+ unless => "/bin/ls /etc/rc3.d/ | /bin/grep nagios-nsa",
+ require => File["/etc/init.d/nagios-nsa"],
+ }
+ service { "nagios-nsa":
+ ensure => "running",
+ pattern => "riseup-nagios-server.pl",
+ hasstatus => true,
+ require => [File["/etc/nagios_nsa.cfg"],
+ Exec["nagios_nsa_init_script"],
+ Package["libnet-irc-perl"],
+ Service['nagios'] ],
+ }
+
+ nagios_command {
+ "notify-by-irc":
+ command_line => '/usr/local/bin/riseup-nagios-client.pl "$HOSTNAME$ ($SERVICEDESC$) $NOTIFICATIONTYPE$ n.$SERVICEATTEMPT$ $SERVICESTATETYPE$ $SERVICEEXECUTIONTIME$s $SERVICELATENCY$s $SERVICEOUTPUT$ $SERVICEPERFDATA$"';
+ "host-notify-by-irc":
+ command_line => '/usr/local/bin/riseup-nagios-client.pl "$HOSTNAME$ ($HOSTALIAS$) $NOTIFICATIONTYPE$ n.$HOSTATTEMPT$ $HOSTSTATETYPE$ took $HOSTEXECUTIONTIME$s $HOSTOUTPUT$ $HOSTPERFDATA$ $HOSTLATENCY$s"';
+ }
+}
diff --git a/templates/irc_bot/nagios-nsa.sh.erb b/templates/irc_bot/nagios-nsa.sh.erb
new file mode 100644
index 0000000..61cc063
--- /dev/null
+++ b/templates/irc_bot/nagios-nsa.sh.erb
@@ -0,0 +1,71 @@
+#! /bin/sh
+
+### BEGIN INIT INFO
+# Provides: nagios-nsa
+# Required-Start: $remote_fs $syslog $nagios
+# Required-Stop: $remote_fs $syslog $nagios
+# Default-Start: 2 3 4 5
+# Default-Stop: 1 6 0
+# Short-Description: Nagios Simple IRC Agent
+### END INIT INFO
+
+PIDFILE=<%= nagios_nsa_pidfile %>
+SOCKFILE=<%= nagios_nsa_socket %>
+
+. /lib/lsb/init-functions
+
+start() {
+ log_daemon_msg "Starting nagios IRC bot" "nagios-nsa"
+ if start-stop-daemon --start --quiet --oknodo --pidfile $PIDFILE --user nagios --exec /usr/local/bin/riseup-nagios-server.pl; then
+ log_end_msg 0
+ else
+ log_end_msg 1
+ fi
+}
+
+stop () {
+ log_daemon_msg "Stopping nagios IRC bot" "nagios-nsa"
+ if start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE; then
+ log_end_msg 0
+ else
+ log_end_msg 1
+ fi
+}
+
+remove_socket() {
+ [ -e $SOCKFILE ] && rm $SOCKFILE
+}
+
+cleanup() {
+ if [ -r $PIDFILE ]; then
+ ps -p `cat $PIDFILE` | grep -v 'PID' || {
+ echo "not running"
+ remove_socket
+ }
+ else
+ echo "no pid file"
+ remove_socket
+ fi
+}
+
+case $1
+in
+ start)
+ start
+ ;;
+ stop)
+ stop
+ ;;
+ restart)
+ stop
+ cleanup
+ start
+ ;;
+ status)
+ status_of_proc -p $PIDFILE /usr/local/bin/riseup-nagios-server.pl && exit 0 || exit $?
+ ;;
+ *)
+ log_action_msg "Usage: /etc/init.d/nagios-nsa {start|stop|restart|status}"
+ exit 1
+esac
+
diff --git a/templates/irc_bot/nsa.cfg.erb b/templates/irc_bot/nsa.cfg.erb
new file mode 100644
index 0000000..7cba62c
--- /dev/null
+++ b/templates/irc_bot/nsa.cfg.erb
@@ -0,0 +1,13 @@
+%Nsa = (
+ 'socket' => '<%= nagios_nsa_socket %>',
+ 'server' => '<%= nagios_nsa_server %>',
+ 'port' => '<%= nagios_nsa_port %>',
+ 'nickname' => '<%= nagios_nsa_nickname %>',
+ 'password' => '<%= nagios_nsa_password %>',
+ # this needs libio-socket-ssl-perl
+ # doesn't actually works because Net::IRC is braindead and tries to use IO::Socket::SSL->read/write instead of the builtin print, see http://search.cpan.org/dist/IO-Socket-SSL/SSL.pm
+ #'SSL' => 0,
+ 'channel' => '<%= nagios_nsa_channel %>',
+ 'pidfile' => '<%= nagios_nsa_pidfile %>', # set to undef to disable
+ 'realname' => "<%= nagios_nsa_realname %>",
+);