nagios-fifo.pl 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. #!/usr/bin/perl
  2. # What this script does :
  3. # -----------------------
  4. # 1/ check nagios.log
  5. # 2/ setup an array of alerts
  6. # 3/ ability to remove-change alerts on new notification for same host/[service]
  7. # 4/ dialog with livestatus to replay full alerts on load/setup : irssi command /nagrefresh
  8. # 5/ define !recheck to nagios
  9. # 6/ ability to define chan/server on irssi configuration instead of bot config.
  10. #
  11. # What it should do :
  12. # -------------------
  13. # TODO
  14. # define !ack irc command
  15. # use %ACK_INDEX by alert type HOST / SERVICE
  16. # use %ACK_INDEX_LEVEL by alert type CRIT/UP/DOWN/WARN/UNK…
  17. use strict;
  18. use vars qw($VERSION %IRSSI);
  19. use Irssi;
  20. use POSIX "sys_wait_h";
  21. use POSIX qw(strftime);
  22. use Term::ANSIColor qw/ :constants /;
  23. use Fcntl; # provides `O_NONBLOCK' and `O_RDONLY' constants
  24. ##########################################################################
  25. # Part A : script configuration / Prototypes
  26. # Put signals to irssi ###################################################
  27. our ( $FIFO, # fifo absolute filename (expanded from Irssi config)
  28. $FIFO_HANDLE, # fifo filehandle for `open' et al.
  29. $FIFO_TAG ); # fifo signal tag for `input_add'
  30. $VERSION = "0.4.1";
  31. %IRSSI = (
  32. authors => 'asr',
  33. contact => 'root@lautre.net',
  34. name => 'nagios-ack',
  35. description => 'ack nagios alerts in irc / follow nagios log',
  36. license => 'GPLv2',
  37. url => 'http://www.lautre.net/',
  38. changed => '20141006',
  39. modules => ''
  40. );
  41. my $PRINTF = "/usr/bin/printf";
  42. # Put signals to irssi ###################################################
  43. Irssi::settings_add_str($IRSSI{name}, # default fifo_remote_file
  44. 'fifo_remote_file', '/home/tc-14/var/nagios-fifo'); #
  45. Irssi::settings_add_str("nagios_ack", "nagios_ack_channel", "#main_channel"); # see also etc/config.template
  46. Irssi::settings_add_str("nagios_ack", "nagios_ack_nick", ""); # any user (none by default)
  47. Irssi::settings_add_str("nagios_ack", "nagios_live", "/var/lib/nagios3/rw/live");
  48. Irssi::settings_add_str("nagios_ack", "nagios_command", "/var/lib/nagios3/rw/nagios.cmd");
  49. #Irssi::command_bind( 'ack', \&nagios_ack );
  50. #Irssi::command_bind( 'nagstat', \&nagios_status );
  51. Irssi::command_bind( 'nagrefresh', \&nagios_query_status );
  52. # CONFIG: point this where your Nagios configuration files live
  53. #my $nagioslog = "/var/log/nagios3/nagios.log";
  54. # To be used to check immediately / hosts-stats
  55. my $nagioscmd = Irssi::settings_get_str("nagios_command");
  56. my $nagioslive = Irssi::settings_get_str("nagios_live");
  57. my $nagios_ack_channel= Irssi::settings_get_str("nagios_ack_channel");
  58. my $nagios_ack_nick= Irssi::settings_get_str("nagios_ack_nick");
  59. my %renot; # { "host" or "host:service" => time_last_notification }
  60. my @cmdqueue = ();
  61. my %ignore = ();
  62. my @ACKS; # [ hostname, service, state, plugin_output, last_state_change, ACKnowledged ] );
  63. my %ACK_Ind;
  64. my %C = (
  65. K => "\x0301", # 00. White
  66. B => "\x0302", # 01. Black
  67. G => "\x0303", # 02. Blue (Navy)
  68. R => "\x0304", # 03. Green
  69. # 04. Red
  70. V => "\x0306", # 05. Brown (Maroon)
  71. O => "\x0307", # 06. Purple
  72. Y => "\x0308", # 07. Orange
  73. Gg => "\x0309", # 08. Yellow
  74. # 09. Light Green (Lime)
  75. C => "\x0311", # 10. Teal (Green/Blue Cyan)
  76. Bb => "\x0312", # 11. Light Cyan (Cyan) (Aqua)
  77. Ma => "\x0313", # 12. Light Blue (Royal)
  78. Gr => "\x0314", # 13. Pink (Light Purple) (Fuchsia)
  79. W => "\x0315", # 14. Grey
  80. # 15. Light Grey (Silver)
  81. Z => "\x03",
  82. );
  83. # Numeric to string conversion of nagios status
  84. # 0..4 : hosts
  85. # 10..14 : services
  86. my @NagStates = qw/UP DOWN WARNING UNKNOWN .. .. .. .. .. ..
  87. OK WARNING CRITICAL UNKNOWN/;
  88. # Bold: U+0002 ("0x02") — Example: ^Bold Text^ whereas ^ represents the control character.
  89. # Italics: U+001D ("0x1D") — Example: ^Italicized Text^ whereas ^ represents the control character.
  90. # Underline: U+001F ("0x1F") — Example: ^Underlined Text^ whereas ^ represents the control character.
  91. # The control character used for color is U+0003 ("0x03").
  92. my $state_to_color = {
  93. OK => $C{G},
  94. UP => $C{G},
  95. WARNING => $C{Y},
  96. CRITICAL => $C{R},
  97. DOWN => $C{V},
  98. UNKNOWN => $C{Gr},
  99. };
  100. # Global use to limit memory use. Probably a bad idea : better to check
  101. # where is the memory leak.
  102. my ($status_line);
  103. my @match;
  104. my $msg;
  105. my $i;
  106. my $stat;
  107. my $message;
  108. my ($type,$data);
  109. my ($d,$type,$host,$service,$state,$output);
  110. my ( $host, $svc, $state, $id );
  111. my ($server, $nick, $addr, $target);
  112. my ( $param, $server, $window );
  113. my (@issue, $issue);
  114. #my $state_to_color = { OK => '', UP => '', WARNING => '', CRITICAL => '', DOWN => '', UNKNOWN => '' };
  115. # Alert Acknowledment ####################################################
  116. my $last_alert;
  117. my $DEBUG=Irssi::settings_get_str("nagios_ack_nick");
  118. # Simple subs ############################################################
  119. sub TRUE() { 1 } # some constants [perlsyn(1)
  120. sub FALSE() { "" } # "Constant Functions"]
  121. sub DEBUG(@) { print "%B", join(":", @_),"%n" }# DEBUG thingy
  122. sub time2date($) {
  123. ($d)=@_;
  124. return strftime("%d/%m/%y %H:%M", localtime($d));
  125. }
  126. ##########################################################################
  127. # Part B : user Actions ##################################################
  128. # Acknowledge alerts #####################################################
  129. # Global use to limit memory use. Probably a bad idea : better to check
  130. # where is the memory leak.
  131. # Four unused subs. Still there to be implemented later
  132. sub parse_status();
  133. sub nagios_ack($$$);
  134. sub nagios_check($$$);
  135. sub nagios_inject;
  136. #sub nagios_status();
  137. # Return alert ID "[FF01]"
  138. # F : caracter to display (! : ; C : change ; + : new alert ; - : green flag ; ? : green but not found)
  139. # I : numeric ID
  140. # state : state string, from @NagStates or %state_to_color
  141. sub format_alert_id($$$$); # ($Flag,$I,$state,$acked)
  142. # Add alert to array / index
  143. # returns array (ID,char) : ID of new alert (-1 if not inserted) ; char in !,c,?,+,-.
  144. sub insert_alert($$$$$$); #( $host, $svc, $state, $msg, $d )
  145. ##########################################################################
  146. # Part C : Logfile management ############################################
  147. # disable fifo and erase fifo file
  148. sub destroy_fifo($); # [2004-08-14]
  149. # Open logfile/fifo
  150. sub open_fifo($); # [2004-08-14]
  151. # read from fifo
  152. # (called by fifo input signal)
  153. sub read_fifo(); # [2004-08-14]
  154. # Read logfile ###########################################################
  155. # create named fifo and open it for input
  156. # (called on script load and fifo name changes)
  157. sub create_fifo($); # [2004-08-14]
  158. # Query nagios ###########################################################
  159. sub nagios_query_status($);
  160. ##########################################################################
  161. # Part D : Alert processing ##############################################
  162. # display a line resuming the alert
  163. # ($server,$chan,$alert_id,$prefix) -> alert_id from @ACKS
  164. sub display_alert($$$$);
  165. # Search for services/host informations, and post them to IRC ############
  166. # Delimiter : ; for logs; @ for direct nagios custom notification command
  167. # one parameter : the logline to parse.
  168. sub parse_nagios_log($);
  169. # Use alert fields to print and insert it
  170. # timestamp, alert-type, hostname, state, plugin output, service_name
  171. sub handle_alert($$$$$$$$); # $d,$type,$host,$state,$output,$service,$acked
  172. ##########################################################################
  173. # IRSSI Events ###########################################################
  174. # create new fifo (erase any old) and get command prefix
  175. # (called on script loading and on user /set)
  176. sub setup(); # [2004-08-13]
  177. # Interact with IRC chan users
  178. sub event_privmsg ($$$$);
  179. ##########################################################################
  180. # References #############################################################
  181. ##########################################################################
  182. # REFERENCES
  183. # ----------
  184. #
  185. # This script is mainly adapted from 3 other scripts related to nagios :
  186. #
  187. # https://github.com/zorkian/nagios-irc-bot/blob/master/nagiosirc.pl
  188. # http://www.update.uu.se/~zrajm/programs/irssi-scripts/fifo_remote.pl-0.5
  189. # https://github.com/mikegrb/irssi-scripts/blob/master/nagios-ack.pl
  190. ##########################################################################
  191. # CODE ###################################################################
  192. ##########################################################################
  193. ##########################################################################
  194. # Part B : user Actions ##################################################
  195. sub parse_status() {
  196. return $1 if $last_alert =~ /^PROBLEM - (\S+) is DOWN/;
  197. return ($1, $2) if $last_alert =~ /^PROBLEM - (\S+) on (\S+) is/;
  198. return;
  199. }
  200. sub nagios_ack($$$) {
  201. ( $param, $server, $window ) = @_;
  202. $msg='';
  203. @issue = parse_status();
  204. if (!@issue) {
  205. #$window->print("Failed to parse last status: $last_alert");
  206. }
  207. # $host / sticky / notif / persistant / user
  208. ($id,$message)=split " ",$param;
  209. if (($id =~ /^#(\d+)/) && ($id <= scalar @ACKS)) {
  210. $id=$1;
  211. $i=time;
  212. if ($ACKS[$id]->[5] == 1) {
  213. # Already ACKed, print an error.
  214. $msg = " ACK : impossible, c'est dejà fait" ;
  215. display_alert($server,$nagios_ack_channel,$id,' '
  216. # format_alert_id(' ', $id, $ACKS[$id]->[2], $ACKS[$id]->[5])
  217. );
  218. } elsif ($ACKS[$id]->[1] ne "") {
  219. $msg = " ACK ".$id." \"ACKNOWLEDGE_SVC_PROBLEM;$ACKS[$id]->[0];$ACKS[$id]->[1];2;0;1;nagiosadmin;$message\" $i > $nagioscmd";
  220. Irssi::active_server->command('MSG ' . $DEBUG . " ".
  221. `$PRINTF "[\%lu] ACKNOWLEDGE_SVC_PROBLEM;$ACKS[$id]->[0];$ACKS[$id]->[1];2;0;1;nagiosadmin;$message" $i> $nagioscmd`
  222. );
  223. } else {
  224. $msg = " ACK ".$id." \"ACKNOWLEDGE_HOST_PROBLEM;$ACKS[$id]->[0];2;0;1;nagiosadmin;$message\" $i > $nagioscmd";
  225. Irssi::active_server->command('MSG ' . $DEBUG . " ".
  226. `$PRINTF "[\%lu] ACKNOWLEDGE_HOST_PROBLEM;$ACKS[$id]->[0];2;0;1;nagiosadmin;$message" $i > $nagioscmd`
  227. );
  228. }
  229. $ACKS[$id]->[5] = 1;
  230. Irssi::active_server->command('MSG ' . $nagios_ack_channel . $msg);
  231. } else {
  232. $server->command ( "msg ".$nagios_ack_channel. " Usage : !nagios ACK #<alert_num> <ack message to be sent to nagios>. Please validate first, with a !nagios list #<alert_num>");
  233. display_alert($server,$nagios_ack_channel,$id,' '
  234. # format_alert_id(' ', $id, $ACKS[$id]->[2], $ACKS[$id]->[5])
  235. ) if $id =~ /^(\d+)/ ;
  236. }
  237. }
  238. sub nagios_check($$$) {
  239. #1412375470;filer2;DISK_all;2;W=10% C=5%
  240. ( $param, $server, $window ) = @_;
  241. @issue = parse_status();
  242. if (!@issue) {
  243. #$window->print("Failed to parse last status: $last_alert");
  244. }
  245. $message = " CHECK ".$param . join ' ', reverse @issue;
  246. Irssi::active_server->command('MSG ' . $DEBUG . $message);
  247. # handle_alert($$$$$$$) { # $d,$type,$host,$state,$output,$service }
  248. }
  249. sub nagios_inject {
  250. $last_alert = shift;
  251. }
  252. #sub nagios_status {
  253. # (undef, undef, $window) = @_;
  254. # $issue = join ',', map { "'" . $_ . "'" } reverse parse_status();
  255. # $window->print("Last issue: '$last_alert' ($issue)");
  256. #
  257. #}
  258. # Return alert ID
  259. sub format_alert_id($$$$) {
  260. my ($Flag,$I,$state,$acked)=@_;
  261. my $M=sprintf('%02d', scalar @ACKS % 100);
  262. my $N=sprintf('%02d', $I % 100);
  263. if (($I == 0) && (scalar @ACKS == 0)) {
  264. return "[".($acked==0?'!':' ').$Flag." ]/$M ";
  265. } else {
  266. return "[".($acked==0?'!':' ').$Flag.$state_to_color->{$state}.$N.$C{Z}."]/$M ";
  267. }
  268. }
  269. # Add alert to array / index
  270. sub insert_alert($$$$$$) {
  271. # returns ID of new alert ; -1 if not inserted.
  272. #Irssi::print(">> On vire $host/$svc");
  273. my $i;
  274. my $acked;
  275. ( $host, $svc, $state, $msg, $d, $acked ) = @_;
  276. # ALERT
  277. if ( $state eq 'WARNING' || $state eq 'CRITICAL' || $state eq 'UNKNOWN' || $state eq 'DOWN' ) {
  278. while ($i <= $#ACKS) {
  279. # Update, or insert ?
  280. if (($ACKS[$i]->[0] eq $host) && ($ACKS[$i]->[1] eq $svc)) {
  281. $ACKS[$i]->[4]=$d;
  282. Irssi::print(">> found $i");
  283. if ($ACKS[$i]->[2] ne $state) {
  284. # Same alert, but different level
  285. $ACKS[$i]->[2]=$state;
  286. return ($i+1,'c');
  287. } else {
  288. # Same alert
  289. return ($i+1, '!');
  290. # No need to display...
  291. }
  292. }
  293. $i++;
  294. }
  295. # New alert, insert.
  296. push (@ACKS, [ $host, $svc, $state, $msg, $d, $acked ] );
  297. return (scalar @ACKS,'+');
  298. # Clear alert
  299. } else {
  300. # Irssi::print(">> On vire $host/$svc");
  301. $i=0;
  302. # Find alert (need to be used by service/host index)
  303. while ($i <= $#ACKS) {
  304. if (($ACKS[$i]->[0] eq $host) && ($ACKS[$i]->[1] eq $svc)) {
  305. $ACKS[$i] = pop @ACKS;
  306. $i=$#ACKS;
  307. Irssi::print(">> found $i");
  308. return (-1,'-');
  309. }
  310. $i++;
  311. }
  312. return (-1,'?');
  313. }
  314. }
  315. ##########################################################################
  316. # Part C : Logfile management ############################################
  317. # disable fifo and erase fifo file
  318. sub destroy_fifo($) { # [2004-08-14]
  319. my ($fifo) = @_; # get args
  320. if (defined $FIFO_TAG) { # if fifo signal is active
  321. Irssi::input_remove($FIFO_TAG); # disable fifo signal
  322. undef $FIFO_TAG; # and forget its tag
  323. } #
  324. if (defined $FIFO_HANDLE) { # if fifo is open
  325. close $FIFO_HANDLE; # close it
  326. undef $FIFO_HANDLE; # and forget handle
  327. } #
  328. if (-p $fifo) { # if named fifo exists
  329. unlink $fifo; # erase fifo file
  330. undef $FIFO; # and forget filename
  331. } #
  332. return 1; # return
  333. } #
  334. # Open logfile/fifo
  335. sub open_fifo($) { # [2004-08-14]
  336. my ($fifo) = @_; # get args
  337. if (not sysopen $FIFO_HANDLE, $fifo, # open fifo for non-blocking
  338. O_NONBLOCK | O_RDONLY) { # reading
  339. print CLIENTERROR "could not open nagios logfile for reading";
  340. return ""; #
  341. } #
  342. Irssi::input_remove($FIFO_TAG) # disable fifo reading signal
  343. if defined $FIFO_TAG; # if there is one
  344. $FIFO_TAG = Irssi::input_add # set up signal called when
  345. fileno($FIFO_HANDLE), INPUT_READ, # there's input in the pipe
  346. \&read_fifo, ''; #
  347. return 1; #
  348. }
  349. # read from fifo
  350. # (called by fifo input signal)
  351. sub read_fifo() { # [2004-08-14]
  352. # Read logfile ###########################################################
  353. foreach (<$FIFO_HANDLE>) { # for each input line
  354. chomp; # strip trailing newline
  355. parse_nagios_log($_); #if (/ALERT/ && /HARD;/);
  356. #Irssi::active_win->print( # show incoming commands (debug)
  357. # "\u$IRSSI{name} received command: \"$_\"", #
  358. # MSGLEVEL_CLIENTNOTICE); #
  359. # Irssi::active_win->command($_); # run incoming commands
  360. } #
  361. open_fifo($FIFO); # re-open fifo
  362. # TODO: Is the above re-opening of fifo really necessary? -- If not
  363. # invoked here `read_fifo' is called repeatedly, even though no input
  364. # is to be found on the fifo. (This seems a waste of resources to me.)
  365. }
  366. # create named fifo and open it for input
  367. # (called on script load and fifo name changes)
  368. sub create_fifo($) { # [2004-08-14]
  369. my ($new_fifo) = @_; # get args
  370. if (not -p $new_fifo) { # create fifo if non-existant
  371. if (system "mkfifo '$new_fifo' &>/dev/null" and
  372. system "chmod 777 '$new_fifo' &>/dev/null" and
  373. system "mknod '$new_fifo' &>/dev/null"){
  374. print CLIENTERROR "`mkfifo' failed -- could not create named pipe";
  375. # TODO: capture `mkfifo's stderr and show that here
  376. return ""; #
  377. } #
  378. } #
  379. $FIFO = $new_fifo; # remember fifo name
  380. open_fifo($new_fifo); # open fifo for reading
  381. } #
  382. # Query nagios ###########################################################
  383. sub nagios_query_status($){
  384. # 1412478149;hyppocampe;apt;2;CRITICAL : unknown: qemu-utils, qemu-kvm, qemu-keymaps
  385. my ($option)=@_;
  386. my @unixcat;
  387. my $unixline;
  388. my $acked;
  389. $nagioslive = Irssi::settings_get_str("nagios_live");
  390. foreach $acked (0,1) {
  391. foreach $unixline ( `echo "GET services
  392. Columns: last_state_change host_name display_name state plugin_output
  393. Filter: state > 0
  394. Filter: acknowledged = $acked
  395. And: 2" | unixcat $nagioslive` ) {
  396. chomp $unixline;
  397. ($d,$host,$service,$state,$output)=split /;/,$unixline;
  398. handle_alert($option,$d,'SERVICE',$host,$NagStates[$state+10],$output,$service,$acked);
  399. Irssi::print("%B>>%n $unixline", MSGLEVEL_CLIENTCRAP);
  400. }
  401. }
  402. return;
  403. foreach $acked (0,1) {
  404. foreach $unixline ( `echo "GET hosts
  405. Columns: last_state_change host_name state plugin_output
  406. Filter: state > 0
  407. Filter: acknowledged = 0
  408. And: 2" | unixcat $nagioslive` ) {
  409. chomp $unixline;
  410. ($d,$host,$state,$output)=split /;/,$unixline;
  411. handle_alert($option,$d,'HOST',$host,$NagStates[$state],$output,"",$acked);
  412. Irssi::print("%B>>%n $unixline", MSGLEVEL_CLIENTCRAP);
  413. }
  414. }
  415. }
  416. ##########################################################################
  417. # Part D : Alert processing ##############################################
  418. sub display_alert($$$$){
  419. my ($server,$chan,$alert_id,$prefix) = @_;
  420. #Irssi::print("... $alert_id");
  421. return unless defined $ACKS[$alert_id];
  422. # @ACKS; # [ hostname, service, state, plugin_output, last_state_change, ACKnowledged ] );
  423. # my ($server,$chan,$date,$prefix,$state,$acked,$hostname,$service,$output) = @_;
  424. $prefix=format_alert_id($prefix,$alert_id,$ACKS[$alert_id]->[2],$ACKS[$alert_id]->[5]) ;
  425. #format_alert_id(' ', $i, $K->[2], $K->[5]),
  426. $server->command ( 'msg ' . $chan .
  427. " NAGIOS ". time2date ($ACKS[$alert_id]->[4])." ".
  428. $prefix. " ". $state_to_color->{$ACKS[$alert_id]->[2]}.$ACKS[$alert_id]->[0]."/".$ACKS[$alert_id]->[1].$C{Z}.
  429. " / $ACKS[$alert_id]->[2]".($ACKS[$alert_id]->[5]?" Acked":"")." : $ACKS[$alert_id]->[3]"
  430. );
  431. }
  432. # Search for services/host informations, and post them to IRC ############
  433. # Delimiter : ; for logs; @ for direct nagios custom notification command
  434. sub parse_nagios_log($){
  435. my $option="";
  436. $d=0; $status_line=""; $host="";$output="";$service="";
  437. $status_line=shift;
  438. ### log :
  439. # [1412330770] SERVICE ALERT: ella;IMAPs_LOGIN;OK;SOFT;2;OK - CO1N OK LOGIN Ok.
  440. # /\[\d+\] (\w+) ALERT: (\w+);(\w+);(\w+);HARD;(\d+);(.+)/
  441. # [1410969598] HOST ALERT: filou;DOWN;SOFT;1;PING CRITICAL - Paquets perdus = 100%
  442. # [TIMESTAMP] PROCESS type ALERT: host;service;STATE1;HARD;num;commentaire
  443. if (@match=$status_line =~ /\[?(\d+)\]? HOST ALERT: ([^@;]+)[@;]([^;@]+)[@;]HARD[@;][^;@]*[@;](.+)/) {
  444. # HOST ########################
  445. ($d,$host,$state,$output)=@match;
  446. handle_alert($option,$d,"HOST",$host,$state,$output,$service,0);
  447. # SERVICE #####################
  448. } elsif (@match=$status_line =~ /\[?(\d+)\]? (\w+) ALERT: ([^;@]+)[@;]([^;@]+)[@;]([^;@]+)[@;]HARD[@;][^;@]*[@;](.+)/) {
  449. ($d,$type,$host,$service,$state,$output)=@match;
  450. $service=~s/[^\w\d_-]/_/g;
  451. handle_alert($option,$d,$type,$host,$state,$output,$service,0);
  452. # OTHER #######################
  453. } elsif (@match=$status_line =~ /\[\d+\] (\w+) ALERT: (.*)/) {
  454. ($type,$data)=@match;
  455. Irssi::print( "%B>>%n $IRSSI{name} $type - $data", MSGLEVEL_CLIENTCRAP) unless ($status_line =~ /[;@]SOFT[@;]/);
  456. # FALLBACK ####################
  457. } else {
  458. Irssi::print( #
  459. "%B>>%n $IRSSI{name} received message: \"$_\"",
  460. MSGLEVEL_CLIENTCRAP); #
  461. next
  462. }
  463. }
  464. # Use alert fields to print and insert it
  465. sub handle_alert($$$$$$$$) { # $d,$type,$host,$state,$output,$service,acked
  466. my $option;
  467. my $acked;
  468. # Temporisation
  469. ($option,$d,$type,$host,$state,$output,$service,$acked)=@_;
  470. next if exists $renot{"$host:$service"} && $renot{"$host:$service"} >= time() - 5;
  471. $renot{"$host:$service"} = time();
  472. # HOST or SERVICE ?
  473. ($id,$stat) = insert_alert($host,$service,$state,$output,$d,$acked);
  474. # Silently ignore previously sent/acked alerts
  475. Irssi::print(">> $nagios_ack_channel,$d,$id,$state,$acked,$host,$service,$output");
  476. return if $id == -1;
  477. $nagios_ack_channel= Irssi::settings_get_str("nagios_ack_channel");
  478. display_alert(Irssi::active_server,$nagios_ack_channel,$id,$stat),
  479. unless ($option eq "silent");
  480. }
  481. ##########################################################################
  482. # IRSSI Events ###########################################################
  483. # create new fifo (erase any old) and get command prefix
  484. # (called on script loading and on user /set)
  485. sub setup() { # [2004-08-13]
  486. my $new_fifo = Irssi::settings_get_str # setting from Irssi
  487. 'fifo_remote_file'; # (and add path to it)
  488. return if $new_fifo eq $FIFO and -p $FIFO; # do nada if already exists
  489. destroy_fifo($FIFO) if -p $FIFO; # destroy old fifo
  490. create_fifo($new_fifo) # create new fifo
  491. and $FIFO = $new_fifo; # and remember that fifo
  492. # To ADD :
  493. # request to livestatus to fetch stored alerts
  494. }
  495. # Interact with IRC chan users
  496. sub event_privmsg($$$$) {
  497. # Commamd channel
  498. my $K;
  499. my ($server, $data, $nick, $mask) =@_;
  500. my ($target, $text, $arg) = $data =~ /^(\S*)\s:(.*)/;
  501. #print ( "C:$target X:$text A:$admin D:$warndate L:$last W:$warn N:$nick D:$data" );
  502. if ( $text =~ /^!nagios ?(.*)/i ) {
  503. $arg=$1;
  504. # If we are not in command channel : NoOP
  505. $nagios_ack_channel=Irssi::settings_get_str("nagios_ack_channel");
  506. Irssi::print(">> $arg - $nagios_ack_channel - $target");
  507. return if $target ne $nagios_ack_channel ;
  508. if ($arg =~ /^refresh ?(.*)/i) {
  509. $arg=$1;
  510. Irssi::print(">> $arg");
  511. if ($arg =~ /\bclear\b/) {
  512. $server->command ( "msg ".$nagios_ack_channel." Local alerts cleared" );
  513. @ACKS=();
  514. }
  515. if ($arg =~ /\bclear\b/) {
  516. nagios_query_status("silent");
  517. } else {
  518. nagios_query_status("");
  519. $server->command ( "msg ".$nagios_ack_channel.
  520. 'Refresh nagios. Use "silent" keyword to disable display.');
  521. }
  522. $server->command ( "msg ".$nagios_ack_channel.
  523. " ".scalar @ACKS." alertes");
  524. }
  525. elsif ($arg =~ /^list ?(.*)/i) {
  526. my $i=0;
  527. # Do you search on pattern (whole database), or a list (reduced database) ?
  528. my $grepto;
  529. my $motif=$1;
  530. my $search_unack=0;
  531. $server->command ( "msg ".$nagios_ack_channel.
  532. " ".scalar @ACKS." alertes");
  533. $motif="" unless defined($motif) ;
  534. $motif="0\$" if $motif =~ /^ack$/i;
  535. $motif="1\$" if $motif =~ /^unack$/i;
  536. $search_unack="1" if $motif eq "";
  537. Irssi::print(">> List : $motif");
  538. foreach $K (@ACKS) {
  539. my $grepto="#$i @$K";
  540. # just display alert fields, with colors.
  541. # See ACKS fields organization
  542. # Field 5 is "Alert has been previously acknowledged"
  543. # display_alert($server,$chan,$date,$prefix,$state,$acked,$hostname,$service,$output)
  544. display_alert($server,$nagios_ack_channel,$i,' '
  545. #format_alert_id(' ', $i, $K->[2], $K->[5]),
  546. #$K->[2],$K->[5],$K->[0],$K->[1],$K->[3]
  547. ) if ( ($grepto =~ /$motif/i) || ($search_unack && ($K->[5]==0)) );
  548. # Display only if : $motif is found, or $motif is empty, and alert is unack
  549. $i++;
  550. }
  551. }
  552. elsif ($arg =~ /^help/i) {
  553. $server->command ( "msg ".$nagios_ack_channel.
  554. " !nagios list [pattern] [ack/unack] : liste des alertes nagios reçues ici");
  555. $server->command ( "msg ".$nagios_ack_channel.
  556. " !nagios help : l'aide");
  557. $server->command ( "msg ".$nagios_ack_channel.
  558. " !nagios ack <#ALERTE> <message> TODO : aquitte l'alerte");
  559. $server->command ( "msg ".$nagios_ack_channel.
  560. " !nagios check <#ALERTE> TODO : recheck une alerte donnée (service/host)");
  561. $server->command ( "msg ".$nagios_ack_channel.
  562. " !nagios refresh [silent] [clear] : interroge le nagios pour avoir la liste de toutes les alertes");
  563. $server->command ( "msg ".$nagios_ack_channel.
  564. " si le mot clef 'clear' est ajouté, il purge les alertes locales");
  565. } elsif ( $arg =~ /^check ?(.*)/i ){
  566. nagios_check($1,$server,undef);
  567. } elsif ( $arg =~ /^ack ?(.*)/i ){
  568. nagios_ack($1,$server,undef);
  569. $server->command ( "msg ".$nagios_ack_channel.
  570. " ".scalar @ACKS." alertes");
  571. } else {
  572. $server->command ( "msg ".$nagios_ack_channel.
  573. " ".scalar @ACKS." alertes");
  574. }
  575. }
  576. return 1;
  577. }
  578. ##########################################################################
  579. # Main ###################################################################
  580. ##########################################################################
  581. print "starting...\n";
  582. # clean up fifo on unload
  583. # (called on /script unload)
  584. Irssi::signal_add_first #
  585. 'command script unload', sub { # [2004-08-13]
  586. my ($script) = @_; # get args
  587. return unless $script =~ # only do cleanup when
  588. /(?:^|\s) $IRSSI{name} # unloading *this* script
  589. (?:\.[^. ]*)? (?:\s|$) /x; #
  590. destroy_fifo($FIFO) if -p $FIFO; # destroy old fifo
  591. Irssi::print("%B>>%n $IRSSI{name} $VERSION unloaded", MSGLEVEL_CLIENTCRAP);
  592. }; #
  593. setup(); # initialize setup values
  594. Irssi::signal_add('event privmsg', 'event_privmsg');
  595. Irssi::signal_add("message public", "event_privmsg");
  596. Irssi::signal_add('setup changed', \&setup); # re-read setup when it changes
  597. print CLIENTCRAP "%B>>%n $IRSSI{name} $VERSION (by $IRSSI{authors}) loaded";
  598. 1;