#!/usr/bin/perl 
# ack_matching.cgi
#
# by Doke Scott, doke at udel dot edu
#
# $Header: /opt/home/doke/work/nagios/RCS/ack_matching,v 1.7 2011/04/25 16:38:09 doke Exp $
#


my $statusfile = "/usr/local/nagios/var/status.dat";  
my $cmdfile = "/usr/local/nagios/var/rw/nagios.cmd";

use strict;   
use warnings;   
use Getopt::Long;

my( $verbose, $help, $ephemeral, $noop, $pattern, $comment, 
    %hosts, %services_by_host, %services_by_service );

$pattern = undef;
$comment = 'acknowledged';
$ephemeral = 0;
$noop = 0;
$verbose = 0;
$help = 0;

sub usage { 
    my( $rc ) = @_;
    print "Usage: $0 [-nvh] -p <pattern> [-c <comment>]
    -p pattern   search for hosts or services matching perl regular expression
		 examples: 'copland', 'sw-ne37-.*', 'mahler.*prtdiag', 
    -c comment   apply this comment
    -e           ephemeral comment, will disappear after next nagios reload
    -n           no-operation, don't actually do it, but show matches
    -v           verbose
    -h           this help
\n";
    exit $rc;
    }


Getopt::Long::Configure ("bundling");
GetOptions(
    'p=s' => \$pattern,
    'c=s' => \$comment,
    'e' => \$ephemeral,
    'n' => \$noop,
    'v+' => \$verbose,
    'h' => \$help,
    );
&usage( 0 ) if ( $help );
&usage( 1 ) if ( ! $pattern );

read_statusfile( $pattern );
ack_hosts( $pattern, $comment );
ack_services( $pattern, $comment );

exit 0;



##########################


sub read_statusfile { 
    my( $pattern ) = @_;
    my( $in_host, $in_service, $host, $service, $current_state, $acked, 
	$state_type );

    open( fH, $statusfile ) || die "can't read-open $statusfile: $!\n";

    while ( <fH> ) { 
	if ( m/^service(status)?\s*{/ ) {    # } make vi happy
	    $in_service = 1;
	    $host = undef;
	    $service = undef;
	    $current_state = 0;
	    $acked = 0;
	    $state_type = 0;
	    }
	elsif ( m/^host(status)?\s*{/ ) {    # } make vi happy
	    $in_host = 1;
	    $host = undef;
	    $current_state = 0;
	    $acked = 0;
	    $state_type = 0;
	    }
	elsif ( m/^\s*host_name=(.*)/ ) { 
	    $host = $1;
	    }
	elsif ( m/^\s*service_description=(.*)/ ) { 
	    $service = $1;
	    }
	elsif ( m/^\s*current_state=(\d+)/ ) { 
	    $current_state = $1;
	    }
	elsif ( m/^\s*problem_has_been_acknowledged=(\d+)/ ) { 
	    $acked = $1;
	    }
	elsif ( m/^\s*state_type=(\d+)/ ) { 
	    $state_type = $1;
	    }
	# { make vi happy 
	elsif ( m/^\s*}\s*$/ ) { 
	    if ( $in_service ) {   
		$verbose && print "host $host, service $service, ", 
		    "current_state $current_state, state_type $state_type, ",
		    "acked $acked\n";
		if ( ( $host =~ m/$pattern/i || $service =~ m/$pattern/i
			    || "$host/$service" =~ m/$pattern/i )
			&& $current_state != 0  # not ok
			&& $state_type == 1	# hard
			&& $acked == 0 ) {	# not acked
		    $verbose && print "found unacked problem $host/$service\n";
		    $services_by_host{ $host }{ $service } = 1;
		    #$services_by_service{ $service }{ $host } = 1;
		}
		$in_service = 0;
		$host = undef;
		$service = undef;
		$current_state = 0;
		$acked = 0;
		$state_type = 0;
		}
	    elsif ( $in_host ) {   
		$verbose && print "host $host, ", 
		    "current_state $current_state, state_type $state_type, ",
		    "acked $acked\n";
		if ( $host =~ m/$pattern/i
			&& $current_state != 0  # not ok
			&& $state_type == 1	# hard
			&& $acked == 0 ) {	# not acked
		    $verbose && print "found unacked problem $host\n";
		    $hosts{ $host } = 1;
		    }
		$in_host = 0;
		$host = undef;
		$current_state = 0;
		$acked = 0;
		$state_type = 0;
		}
	    }
	}
    close fH;
    }



sub ack_hosts { 
    my( $pattern, $comment ) = @_;
    my( $now, $author, $host, $nagios_cmd );

    $verbose && print "acking host problems\n";

    if ( scalar( keys %hosts ) < 1 ) { 
	$verbose && print "no hosts to ack\n";
	return;
	}

    # append results to nagios command file
    if ( ! open( cH, ">$cmdfile" ) ) { 
	die "can't write-open cmdfile $cmdfile: $!\n"; 
	}
    $now = time;
    $author = getlogin || getpwuid( $< ) || 'unknown';
    foreach $host ( sort keys %hosts ) { 
	print "$host\n";

	#[<timestamp>] ACKNOWLEDGE_HOST_PROBLEM;<host>;<sticky ack>;<send notification>;<persistant_comment>;<author>;<comment>
	$nagios_cmd = sprintf "[%lu] ACKNOWLEDGE_HOST_PROBLEM;%s;%d;%d;%d;%s;%s\n",
	    $now, $host, 1, 0, ( ( $ephemeral ) ? 0 : 1 ), $author, $comment;

	$verbose && print "nagios_cmd = $nagios_cmd";
	if ( ! $noop ) { 
	    print cH $nagios_cmd;
	    }
	}
    close cH;
    }




sub ack_services { 
    my( $pattern, $comment ) = @_;
    my( $now, $author, $host, $service, $nagios_cmd );

    $verbose && print "acking service problems\n";

    if ( scalar( keys %services_by_host ) < 1 ) { 
	$verbose && print "no services to ack\n";
	return;
	}

    # append results to nagios command file
    if ( ! open( cH, ">$cmdfile" ) ) { 
	die "can't write-open cmdfile $cmdfile: $!\n"; 
	}
    $now = time;
    $author = getlogin || getpwuid( $< ) || 'unknown';
    foreach $host ( sort keys %services_by_host ) { 
	foreach $service ( sort keys %{$services_by_host{ $host }} ) { 

	    print "$host/$service\n";

	    #[<timestamp>] ACKNOWLEDGE_SVC_PROBLEM;<host>;<service>;<sticky ack>;<send notification>;<persistant_comment>;<author>;<comment>
	    $nagios_cmd = sprintf "[%lu] ACKNOWLEDGE_SVC_PROBLEM;%s;%s;%d;%d;%d;%s;%s\n",
		$now, $host, $service, 1, 0, ( ( $ephemeral ) ? 0 : 1 ), $author, $comment;

	    $verbose && print "nagios_cmd = $nagios_cmd";
	    if ( ! $noop ) { 
		print cH $nagios_cmd;
		}
	    }
	}
    close cH;
    }


