Browse Source

Import initial

Gaétan RYCKEBOER 10 years ago
parent
commit
d64b6f9c07
2 changed files with 479 additions and 0 deletions
  1. 474 0
      bin/nagios-fifo.pl
  2. 5 0
      bin/tailgrep

+ 474 - 0
bin/nagios-fifo.pl

@@ -0,0 +1,474 @@
+#!/usr/bin/perl
+
+#https://github.com/zorkian/nagios-irc-bot/blob/master/nagiosirc.pl
+#http://www.update.uu.se/~zrajm/programs/irssi-scripts/fifo_remote.pl-0.5
+#https://github.com/mikegrb/irssi-scripts/blob/master/nagios-ack.pl
+
+# 1/ check nagios.log
+# 2/ setup an array of alerts
+# 3/ define an ACK command
+# TODO
+# dialog to livestatus to replay full alerts on load/setup
+# define !ack irc command
+# use %ACK_INDEX by alert type HOST / SERVICE
+# use %ACK_INDEX_LEVEL by alert type CRIT/UP/DOWN/WARN/UNK…
+# define !recheck to nagios
+
+use strict;
+use vars qw($VERSION %IRSSI);
+
+use Irssi;
+
+use POSIX "sys_wait_h";
+use POSIX qw(strftime);
+use Term::ANSIColor qw/ :constants /;
+
+use Fcntl;          # provides `O_NONBLOCK' and `O_RDONLY' constants
+
+our ( $FIFO,        # fifo absolute filename (expanded from Irssi config)
+      $FIFO_HANDLE, # fifo filehandle for `open' et al.
+      $FIFO_TAG );  # fifo signal tag for `input_add'
+
+
+# probably not very useful for other people but who knows?
+
+$VERSION = "0.1.0";
+%IRSSI = (
+    authors     => 'asr',
+    contact     => 'root@lautre.net',
+    name        => 'nagios-ack',
+    description => 'ack nagios alerts in irc / follow nagios log',
+    license     => 'GPLv2',
+    url         => 'http://www.lautre.net/',
+    changed     => '20140930',
+    modules     => ''
+);
+
+# Put signals to irssi ###################################################
+Irssi::settings_add_str($IRSSI{name},          # default fifo_remote_file
+    'fifo_remote_file', '/home/tc-14/var/nagios-fifo');     #
+
+Irssi::settings_add_str("nagios_ack", "nagios_ack_channel", "#naglautre");
+#Irssi::settings_add_str("nagios_ack", "nagios_ack_channel", "#root");
+Irssi::settings_add_str("nagios_ack", "nagios_ack_nick", "");
+Irssi::settings_add_str("nagios_ack", "nagios_command", "/var/lib/nagios3/rw/live");
+#Irssi::command_bind( 'ack',     \&nagios_ack );
+#Irssi::command_bind( 'nagstat', \&nagios_status );
+Irssi::command_bind( 'nagrefresh',  \&query_nagios_status );
+
+# CONFIG: point this where your Nagios configuration files live
+#my $nagioslog = "/var/log/nagios3/nagios.log";
+
+# To be used to check immediately / hosts-stats
+my $nagioscmd = "/var/lib/nagios3/rw/live";
+
+my %renot; # { "host" or "host:service" => time_last_notification }
+
+my @cmdqueue = ();
+my %ignore = ();
+my @ACKS;
+my %ACK_Ind;
+
+my %C = (
+	K => "\x0301",   #	00. White
+	B => "\x0302",   #	01. Black
+	G => "\x0303",   #	02. Blue (Navy)
+	R => "\x0304",   #	03. Green
+                        #	04. Red
+	V  => "\x0306",  #	05. Brown (Maroon)
+	O  => "\x0307",  #	06. Purple
+	Y  => "\x0308",  #	07. Orange
+	Gg => "\x0309",  #	08. Yellow
+                        #	09. Light Green (Lime)
+	C  => "\x0311", #	10. Teal (Green/Blue Cyan)
+	Bb => "\x0312", #	11. Light Cyan (Cyan) (Aqua)
+	Ma => "\x0313", #	12. Light Blue (Royal)
+	Gr => "\x0314", #	13. Pink (Light Purple) (Fuchsia)
+	W  => "\x0315", #	14. Grey
+                        #	15. Light Grey (Silver)             
+	Z => "\x03",
+);
+
+#    Bold: U+0002 ("0x02") — Example: ^Bold Text^ whereas ^ represents the control character.
+#    Italics: U+001D ("0x1D") — Example: ^Italicized Text^ whereas ^ represents the control character.
+#    Underline: U+001F ("0x1F") — Example: ^Underlined Text^ whereas ^ represents the control character.
+#    The control character used for color is U+0003 ("0x03"). 
+
+my $state_to_color = {
+	OK => $C{G},
+	UP => $C{G},
+	WARNING => $C{Y},
+	CRITICAL => $C{R},
+	DOWN => $C{V},
+	UNKNOWN => $C{Gr},
+};
+
+my ($status_line);
+my @match;
+my ($msg,$num);
+my ($message,$i);
+my ($type,$data);
+my ($d,$type,$host,$service,$state,$output);
+my ( $host, $svc, $state, $msg, $id );
+
+#my $state_to_color = { OK => '', UP => '', WARNING => '', CRITICAL => '', DOWN => '', UNKNOWN => '' };
+
+# simple subs
+sub TRUE()   { 1  }                            # some constants [perlsyn(1)
+sub FALSE()  { "" }                            # "Constant Functions"]
+sub DEBUG(@) { print "%B", join(":", @_),"%n" }# DEBUG thingy
+# Acknowledge alerts #####################################################
+
+my $last_alert;
+
+my ($server, $msg, $nick, $addr, $target);
+my ( $param, $server, $window ); 
+my (@issue, $issue);
+
+#sub on_public {
+#    ($server, $msg, $nick, $addr, $target) = @_;
+#   # return unless $target eq Irssi::setting_get_str("nagios_ack_channel") && $nick eq Irssi::setting_get_str("nagios_ack_nick");
+#    $last_alert = $msg if $msg =~ m/^PROBLEM/;
+#    return;
+#}
+
+my $DEBUG=Irssi::settings_get_str("nagios_ack_channel"); 
+
+sub nagios_ack {
+    ( $param, $server, $window ) = @_;
+    @issue = parse_status();
+    if (!@issue) {
+        #$window->print("Failed to parse last status: $last_alert");
+    }
+    my $message = " ACK ".$param . join ' ', reverse @issue;
+    Irssi::active_server->command('MSG ' . $DEBUG . $message);
+}
+
+sub nagios_check {
+    ( $param, $server, $window ) = @_;
+    @issue = parse_status();
+    if (!@issue) {
+        #$window->print("Failed to parse last status: $last_alert");
+    }
+    my $message = " CHECK ".$param . join ' ', reverse @issue;
+    Irssi::active_server->command('MSG ' . $DEBUG . $message);
+}
+
+sub nagios_status {
+    (undef, undef, $window) = @_;
+    $issue = join ',', map { "'" . $_ . "'" } reverse parse_status();
+    $window->print("Last issue: '$last_alert' ($issue)");
+
+}
+
+sub parse_status {
+    return $1 if $last_alert =~ /^PROBLEM - (\S+) is DOWN/;
+    return ($1, $2) if $last_alert =~ /^PROBLEM - (\S+) on (\S+) is/;
+    return;
+}
+
+sub nagios_inject {
+    $last_alert = shift;
+}
+
+
+
+sub time2date($) {
+	my ($d)=@_;
+	return strftime("%d/%m/%y %H:%M", localtime($d));
+}
+
+sub mark($$$) {
+	my ($Flag,$I,$state)=@_;
+	my $M=sprintf('%02d', scalar @ACKS % 100);
+	my $N=sprintf('%02d', $I % 100);
+	if ($I < scalar @ACKS) {
+		return "[".$C{W}.$Flag.$C{Z}."  /$M] ";
+	} else {
+		return "[".$C{W}.$Flag.$state_to_color->{$state}.$N.$C{Z}."/$M] ";
+	}
+}
+
+# Add alert to array / index
+sub ackable {
+	#Irssi::print(">> On vire $host/$svc");
+	my $i;
+	( $host, $svc, $state, $msg, $d ) = @_;
+	# ALERT
+	if ( $state eq 'WARNING' || $state eq 'CRITICAL' || $state eq 'UNKNOWN' || $state eq 'DOWN' ) {
+		while ($i <= $#ACKS) {
+			# Update, or insert ?
+			if (($ACKS[$i]->[0] eq $host) && ($ACKS[$i]->[1] eq $svc)) {
+				$ACKS[$i]->[4]=$d;
+				Irssi::print(">> found $i");
+				if ($ACKS[$i]->[2] ne $state) { 
+					# Same alert, but different level
+					$ACKS[$i]->[2]=$state; 
+					return mark ('C', $i, $state);
+				} else { 
+					# Same alert
+					return mark ('!', $i, $state);
+				}
+			}
+			$i++;
+		}
+		# New alert, insert.
+		push (@ACKS, [ $host, $svc, $state, $msg, $d ] );
+		return mark('+',scalar @ACKS,$state);
+	# Clear alert
+	} else {
+#		Irssi::print(">> On vire $host/$svc");
+		$i=0;
+		# Find alert (need to be used by service/host index)
+		while ($i <= $#ACKS) {
+			if (($ACKS[$i]->[0] eq $host) && ($ACKS[$i]->[1] eq $svc)) {
+				$ACKS[$i] = pop @ACKS;
+				$i=$#ACKS;
+				Irssi::print(">> found $i");
+				return mark('-',$i+1,$state);
+			}
+			$i++;
+		}
+		return mark('?',0,$state);
+	}
+}
+
+
+##########################################################################
+# Logfile management #####################################################
+
+# disable fifo and erase fifo file
+sub destroy_fifo($) {                          # [2004-08-14]
+    my ($fifo) = @_;                           #   get args
+    if (defined $FIFO_TAG) {                   #   if fifo signal is active
+        Irssi::input_remove($FIFO_TAG);        #     disable fifo signal
+        undef $FIFO_TAG;                       #     and forget its tag
+    }                                          #
+    if (defined $FIFO_HANDLE) {                #   if fifo is open
+        close $FIFO_HANDLE;                    #     close it
+        undef $FIFO_HANDLE;                    #     and forget handle
+    }                                          #
+    if (-p $fifo) {                            #   if named fifo exists
+        unlink $fifo;                          #     erase fifo file
+        undef $FIFO;                           #     and forget filename
+    }                                          #
+    return 1;                                  #   return
+}                                              #
+
+
+# Open logfile/fifo
+sub open_fifo($) {                             # [2004-08-14]
+    my ($fifo) = @_;                           #   get args
+    if (not sysopen $FIFO_HANDLE, $fifo,       #   open fifo for non-blocking
+        O_NONBLOCK | O_RDONLY) {               #     reading
+        print CLIENTERROR "could not open nagios logfile for reading";
+        return "";                             #
+    }                                          #
+
+    Irssi::input_remove($FIFO_TAG)             #   disable fifo reading signal
+       if defined $FIFO_TAG;                   #     if there is one
+    $FIFO_TAG = Irssi::input_add               #   set up signal called when
+        fileno($FIFO_HANDLE), INPUT_READ,      #     there's input in the pipe
+        \&read_fifo, '';                       #
+    return 1;                                  #
+}             
+
+# read from fifo
+# (called by fifo input signal)
+sub read_fifo() {                              # [2004-08-14]
+# Read logfile ###########################################################
+    foreach (<$FIFO_HANDLE>) {                 #   for each input line
+        chomp;                                 #     strip trailing newline
+	parse_naglog($_); #if (/ALERT/ && /HARD;/);
+        #Irssi::active_win->print(              #   show incoming commands (debug)
+        #    "\u$IRSSI{name} received command: \"$_\"", #
+        #    MSGLEVEL_CLIENTNOTICE);            #
+	#        Irssi::active_win->command($_);     #   run incoming commands
+    }                                          #
+    open_fifo($FIFO);                          #   re-open fifo
+        # TODO: Is the above re-opening of fifo really necessary? -- If not
+        # invoked here `read_fifo' is called repeatedly, even though no input
+        # is to be found on the fifo. (This seems a waste of resources to me.)
+}                 
+
+# create new fifo (erase any old) and get command prefix
+# (called on script loading and on user /set)
+sub setup() {                                  # [2004-08-13]
+    my $new_fifo = Irssi::settings_get_str                #     setting from Irssi
+        'fifo_remote_file';                    #     (and add path to it)
+    return if $new_fifo eq $FIFO and -p $FIFO; #   do nada if already exists
+    destroy_fifo($FIFO) if -p $FIFO;           #   destroy old fifo
+    create_fifo($new_fifo)                     #   create new fifo
+        and $FIFO = $new_fifo;                 #     and remember that fifo
+   # To ADD :
+   # request to livestatus to fetch stored alerts
+}
+
+# create named fifo and open it for input
+# (called on script load and fifo name changes)
+sub create_fifo($) {                           # [2004-08-14]
+    my ($new_fifo) = @_;                       #   get args
+    if (not -p $new_fifo) {                    #   create fifo if non-existant
+        if (system "mkfifo '$new_fifo' &>/dev/null" and
+            system "chmod 777  '$new_fifo' &>/dev/null" and 
+            system "mknod  '$new_fifo' &>/dev/null"){
+            print CLIENTERROR "`mkfifo' failed -- could not create named pipe";
+                # TODO: capture `mkfifo's stderr and show that here
+            return "";                         #
+        }                                      #
+    }                                          #
+    $FIFO = $new_fifo;                         #   remember fifo name
+    open_fifo($new_fifo);                      #   open fifo for reading
+}                                              #
+
+# Query nagios ###########################################################
+sub query_nagios_status(){
+	my @unixcat; 
+	my $unixline;
+        foreach $unixline ( `echo "GET services
+Columns: last_state_change host_name display_name state plugin_output
+Filter: state > 1" | unixcat $nagioscmd` ) {
+		Irssi::print("%B>>%n $unixline", MSGLEVEL_CLIENTCRAP);
+	}
+
+# cat << EOF | unixcat /var/lib/nagios3/rw/live
+# GET services
+# Columns: last_state_change host_name display_name state plugin_output
+# Filter: state > 1
+# EOF
+
+}
+# Parse alert to find vars ###############################################
+sub parse_naglog(){
+	$d=0; $status_line=""; $host="";$output="";$service="";
+# Search for services/host informations, and post them to IRC ############
+#
+# Delimiter : ; for logs; @ for direct nagios custom notification command
+#
+# [1412330770] SERVICE ALERT: ella;IMAPs_LOGIN;OK;SOFT;2;OK - CO1N OK LOGIN Ok.
+# /\[\d+\] (\w+) ALERT: (\w+);(\w+);(\w+);HARD;(\d+);(.+)/
+# [1410969598] HOST ALERT: filou;DOWN;SOFT;1;PING CRITICAL -  Paquets perdus = 100%
+# PROCESS type ALERT: host;service;STATE1;HARD;num;commentaire
+	if (@match=$status_line =~ /\[?(\d+)\]? HOST ALERT: ([^@;]+)[@;](\w+)[@;]HARD[@;].*[@;](.+)/) {
+	# HOST ########################
+		($d,$host,$state,$output)=@match;
+		validate_alert($d,"HOST",$host,$state,$output,$service);
+		
+	# SERVICE #####################
+	} elsif (@match=$status_line =~ /\[?(\d+)\]? (\w+) ALERT: ([^;@]+)[@;]([^;@]+)[@;](\w+)[@;]HARD[@;].*[@;](.+)/) {
+		($d,$type,$host,$service,$state,$output)=@match;
+
+		$service=~s/[^\w\d_-]/_/g;
+		validate_alert($d,$type,$host,$state,$output,$service);
+
+	# OTHER #######################
+	} elsif (@match=$status_line =~ /\[\d+\] (\w+) ALERT: (.*)/) {
+		($type,$data)=@match;
+		Irssi::print( "%B>>%n $IRSSI{name} $type - $data", MSGLEVEL_CLIENTCRAP) unless ($status_line =~ /[;@]SOFT[@;]/);
+	# FALLBACK ####################
+	} else {
+		Irssi::print(                          #
+		    "%B>>%n $IRSSI{name} received command: \"$_\"",
+		    MSGLEVEL_CLIENTCRAP);              #
+		next
+	}
+}
+sub validate_alert($$$$$$) {
+	($d,$type,$host,$state,$output,$service)=@_;
+	next if exists $renot{"$host:$service"} && $renot{"$host:$service"} >= time() - 5;
+	$renot{"$host:$service"} = time();
+
+	#################
+	# HOST
+	$id = ackable($host,$service,$state,$output,$d);
+	$msg = $state_to_color->{$state} . "$id$host is $state".$C{Z}." : $output";
+	#Irssi::print( "%B>>%n $IRSSI{name} $msg", MSGLEVEL_CLIENTCRAP);		
+
+	$last_alert="NAGIOS - $host is $state";
+	$d=time2date($d);
+	$message = " $d - $last_alert - $msg";
+	Irssi::active_server->command('MSG ' . Irssi::settings_get_str("nagios_ack_channel") .
+		" ".$message);
+	#################
+	# SERVICE
+	$id = ackable($host,$service,$state,$output,$d);
+	if ( $id !~ /\[!/ ) {
+	$msg = "$id".$state_to_color->{$state} . "$host:$service".$C{Z}." is $state : $output";
+
+#		Irssi::print( "%B>>%n $IRSSI{name} $msg", MSGLEVEL_CLIENTCRAP);		
+	$last_alert="NAGIOS - $service on $host is $state";
+	$d=time2date($d);
+	$message = " $d - $last_alert - $msg";
+	Irssi::active_server->command('MSG ' . Irssi::settings_get_str("nagios_ack_channel") 
+		." ".$message);
+}
+
+sub event_privmsg {
+	# Commamd channel
+	my $K;
+	my ($server, $data, $nick, $mask) =@_;
+	my ($target, $text) = $data =~ /^(\S*)\s:(.*)/;
+
+        #print ( "C:$target X:$text A:$admin D:$warndate L:$last W:$warn N:$nick D:$data" );
+        if ( $text =~ /^!nagios ?(.*)/i ) {
+		# !nagios [*] :
+		$server->command ( "msg  ".Irssi::settings_get_str("nagios_ack_channel").
+			" ".scalar @ACKS." alertes");
+		return unless $#ACKS > 0;
+		my $i=0;
+		
+		# !nagios list [*] : 
+		if ($1 =~ /^refresh/i) {
+			query_nagios_status();
+		}
+		if ($1 =~ /^list/i) {
+			foreach $K (@ACKS) {
+				$server->command ( "msg  ".Irssi::settings_get_str("nagios_ack_channel").
+					" ". mark(' ',$i++,$K->[2]) ." ".$K->[0]." / $K->[1] / $K->[2] / $K->[3] / ".time2date $K->[4]);
+			}
+		}
+		elsif ($1 =~ /^!help/i) {
+			$server->command ( "msg  ".Irssi::settings_get_str("nagios_ack_channel").
+				" !nagios list : liste des alertes nagios reçuesici");
+			$server->command ( "msg  ".Irssi::settings_get_str("nagios_ack_channel").
+				" !nagios help : l'aide");
+			$server->command ( "msg  ".Irssi::settings_get_str("nagios_ack_channel").
+				" !ack <#ALERTE> <message>: aquitte l'alerte");
+			$server->command ( "msg  ".Irssi::settings_get_str("nagios_ack_channel").
+				" !check : liste des alertes auprès de nagios");
+		}
+                return 1;
+        } elsif ( $text =~ /^!check ?(.*)/i ){
+		nagios_check($1,undef,undef);
+        } elsif ( $text =~ /^!ack ?(.*)/i ){
+		nagios_ack($1,undef,undef);
+	}
+}
+
+##########################################################################
+# Main ###################################################################
+##########################################################################
+
+print "starting...\n";
+
+# clean up fifo on unload
+# (called on /script unload)
+Irssi::signal_add_first                        #
+    'command script unload', sub {             # [2004-08-13]
+        my ($script) = @_;                     #   get args
+        return unless $script =~               #   only do cleanup when
+            /(?:^|\s) $IRSSI{name}             #     unloading *this* script
+             (?:\.[^. ]*)? (?:\s|$) /x;        #
+        destroy_fifo($FIFO) if -p $FIFO;       #   destroy old fifo
+        Irssi::print("%B>>%n $IRSSI{name} $VERSION unloaded", MSGLEVEL_CLIENTCRAP);
+    };                                         #
+
+setup();                                       # initialize setup values
+
+Irssi::signal_add('event privmsg', 'event_privmsg');
+Irssi::signal_add("message public", "event_privmsg");
+#Irssi::signal_add_first("message public", "on_public");
+Irssi::signal_add('setup changed', \&setup);   # re-read setup when it changes
+print CLIENTCRAP "%B>>%n $IRSSI{name} $VERSION (by $IRSSI{authors}) loaded";
+
+1;

+ 5 - 0
bin/tailgrep

@@ -0,0 +1,5 @@
+#!/bin/sh
+filename=$1
+shift
+#echo "parametres : $@"
+[ "$1" != "" ] && cat $filename | grep $* | tail