#!/usr/bin/perl 
# 
# remove matching comments from nagios
#
# $Header: /opt/home/doke/work/nagios/RCS/rm_matching_comments,v 1.8 2012/12/13 17:58:53 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, $rm_problem_comments, $before, $noop, $hspat, $cpat,
    $upat, %host_states, %service_states, %hostcomments, %servicecomments );

$hspat = '.';
$cpat = '.';
$upat = '.';
$rm_problem_comments = 0;
$noop = 0;
$verbose = 0;
$help = 0;

sub usage { 
    my( $rc ) = @_;
    print "Usage: $0 [-nvh] -p <pattern> -c <comment>
    You must specify either -p or -c
    If you give both, both must match, logical AND
    -p pattern   search for services matching perl regular expression
		 examples: 'copland', 'sw-ne37-.*', 'mahler.*prtdiag', 
    -c comment   search for comments matching this perl regular expression
    -u user      search for comments by users matching this perl regular expression
    -r           remove comments from services that are in a pRoblem state
                 Default is to only remove comments from OK hosts or services.
    -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' => \$hspat,
    'c=s' => \$cpat,
    'u=s' => \$upat,
    'r' => \$rm_problem_comments,
    'b' => \$before,
    'n' => \$noop,
    'v+' => \$verbose,
    'h' => \$help,
    );
&usage( 0 ) if ( $help );
&usage( 1 ) if ( ! $hspat && ! $cpat );

$hspat ||= '.';
$cpat ||= '.';

read_statusfile( $hspat, $cpat, $upat, $before );
rm_host_comments( $rm_problem_comments );
rm_service_comments( $rm_problem_comments );

exit 0;



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








sub read_statusfile { 
    my( $hspat, $cpat, $upat, $before ) = @_;
    my( $in_host, $in_service, $in_hostcomment, $in_servicecomment, $host, $service, 
	$current_state, $cid, $comment_data, $entry_time, $author );

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

    $in_host = 0;
    $in_service = 0;
    $in_hostcomment = 0;
    $in_servicecomment = 0;
    $host = undef;
    $cid = 0;
    $comment_data = undef;
    $entry_time = 0;
    $author = undef;

    while ( <fH> ) { 
	if ( ! ( $in_host || $in_service || $in_hostcomment || $in_servicecomment ) ) { 
	    if ( m/^[hs]/ ) { 
		if ( m/^hoststatus\s*{/ ) {    # } make vi happy
		    $in_host = 1;
		    $in_service = 0;
		    $in_hostcomment = 0;
		    $in_servicecomment = 0;
		    $host = undef;
		    $current_state = 0;
		    }
		elsif ( m/^servicestatus\s*{/ ) {    # } make vi happy
		    $in_host = 0;
		    $in_service = 1;
		    $in_hostcomment = 0;
		    $in_servicecomment = 0;
		    $host = undef;
		    $service = undef;
		    $current_state = 0;
		    }
		elsif ( m/^hostcomment\s*{/ ) {    # } make vi happy
		    $in_host = 0;
		    $in_service = 0;
		    $in_hostcomment = 1;
		    $in_servicecomment = 0;
		    $host = undef;
		    $cid = 0;
		    $comment_data = undef;
		    $entry_time = 0;
		    $author = undef;
		    }
		elsif ( m/^servicecomment\s*{/ ) {    # } make vi happy
		    $in_host = 0;
		    $in_service = 0;
		    $in_hostcomment = 0;
		    $in_servicecomment = 1;
		    $host = undef;
		    $service = undef;
		    $cid = 0;
		    $comment_data = undef;
		    $entry_time = 0;
		    $author = undef;
		    }
		}
	    }
	else {    
	    # in something
	    if ( 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+comment_id=(\d+)/ ) { 
		$cid = $1;
		}
	    elsif ( m/^\s+comment_data=(.*)/ ) { 
		$comment_data = $1;
		}
	    elsif ( m/^\s+entry_time=(\d+)/ ) { 
		$entry_time = $1;
		}
	    elsif ( m/^\s+author=(.*)/ ) { 
		$author = $1;
		}

	    # { make vi happy 
	    elsif ( m/^\s*}\s*$/ ) { 
		if ( $in_host ) {   
		    $verbose > 1 && print "found host $host $current_state\n";
		    $host_states{ $host } = $current_state;
		    $in_host = 0;
		    $host = undef;
		    $current_state = 0;
		    }
		
		elsif ( $in_service ) {   
		    $verbose > 1 && print "found service $host/$service $current_state\n";
		    $service_states{ $host }{ $service } = $current_state;
		    $in_service = 0;
		    $host = undef;
		    $service = undef;
		    $current_state = 0;
		    }

		elsif ( $in_hostcomment ) {   
		    if ( $host =~ m/$hspat/io 
			    && $comment_data =~ m/$cpat/io 
			    && $author =~ m/$upat/io ) {
			$verbose && print "found host comment $cid $host $author $comment_data\n";
			$hostcomments{ $cid }{ 'host' } = $host;
			$hostcomments{ $cid }{ 'comment_data' } = $comment_data;
			$hostcomments{ $cid }{ 'entry_time' } = $entry_time;
			$hostcomments{ $cid }{ 'author' } = $author;
			}
		    $in_hostcomment = 0;
		    $host = undef;
		    $cid = 0;
		    $comment_data = undef;
		    $entry_time = 0;
		    $author = undef;
		    }

		elsif ( $in_servicecomment ) {   
		    if ( ( $host =~ m/$hspat/io || $service =~ m/$hspat/io
				|| "$host/$service" =~ m/$hspat/io )
			    && $comment_data =~ m/$cpat/io 
			    && $author =~ m/$upat/io )  { 
			$verbose && print "found service comment $cid $host/$service $author $comment_data\n";
			$servicecomments{ $cid }{ 'host' } = $host;
			$servicecomments{ $cid }{ 'service' } = $service;
			$servicecomments{ $cid }{ 'comment_data' } = $comment_data;
			$servicecomments{ $cid }{ 'entry_time' } = $entry_time;
			$servicecomments{ $cid }{ 'author' } = $author;
		    }
		    $in_servicecomment = 0;
		    $host = undef;
		    $service = undef;
		    $cid = 0;
		    $comment_data = undef;
		    $entry_time = 0;
		    $author = undef;
		    }
		}
	    }
	}
    close fH;
    }




sub rm_host_comments { 
    my( $rm_problem_comments ) = @_;
    my( $now, $host, $nagios_cmd, $cid, $n );

    $verbose && print "removing host comments\n";

    $n = 0;
    foreach $cid ( keys %hostcomments ) { 
	next unless ( $cid > 0 );
	next unless ( defined $hostcomments{ $cid }{ 'host' } );
	$host = $hostcomments{ $cid }{ 'host' };
	next unless ( $host_states{ $host } == 0 
	    || $rm_problem_comments );
	$n++;
	}
    if ( $n == 0 ) { 
	$verbose && print "no host comments to rm\n";
	return;
	}

    $verbose && print "$n host comments to rm\n";

    # append comment deletion commands to nagios command file
    if ( ! open( cH, ">$cmdfile" ) ) { 
	die "can't write-open cmdfile $cmdfile: $!\n"; 
	}
    $now = time;
    foreach $cid ( sort sort_hostcomments keys %hostcomments ) { 
	next unless ( $cid > 0 );
	next unless ( defined $hostcomments{ $cid }{ 'host' } );
	$host = $hostcomments{ $cid }{ 'host' };
	next unless ( $host_states{ $host } == 0 
	    || $rm_problem_comments );

	printf "%s:  %s  %s\n", $host, 
	    $hostcomments{ $cid }{ 'author' },
	    $hostcomments{ $cid }{ 'comment_data' };

	#[<timestamp>] DEL_HOST_COMMENT;<comment_id>
	$nagios_cmd = sprintf "[%lu] DEL_HOST_COMMENT;%lu\n",
	    $now, $cid;

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


sub sort_hostcomments { 
    return $hostcomments{$a}{'host'} cmp $hostcomments{$b}{'host'};
    } 





sub rm_service_comments { 
    my( $rm_problem_comments ) = @_;
    my( $now, $author, $host, $service, $cid, $nagios_cmd, $n );

    $verbose && print "removing service comments\n";

    $n = 0;
    foreach $cid ( keys %servicecomments ) { 
	next unless ( $cid > 0 ); 
	next unless ( defined $servicecomments{ $cid }{ 'host' } ); 
	next unless ( defined $servicecomments{ $cid }{ 'service' } ); 
	$host = $servicecomments{ $cid }{ 'host' }; 
	$service = $servicecomments{ $cid }{ 'service' }; 
	next unless ( $service_states{ $host }{ $service } == 0 
	    || $rm_problem_comments );
	$n++;
	}
    if ( $n == 0 ) { 
	$verbose && print "no service comments to rm\n";
	return;
	}

    $verbose && print "$n service comments to rm\n";

    # 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 $cid ( sort sort_servicecomments keys %servicecomments ) { 
	next unless ( $cid > 0 ); 
	next unless ( defined $servicecomments{ $cid }{ 'host' } ); 
	next unless ( defined $servicecomments{ $cid }{ 'service' } ); 
	$host = $servicecomments{ $cid }{ 'host' }; 
	$service = $servicecomments{ $cid }{ 'service' }; 
	next unless ( $service_states{ $host }{ $service } == 0 
	    || $rm_problem_comments );

	printf "%s/%s:  %s  %s\n", $host, $service, 
	    $servicecomments{ $cid }{ 'author' },
	    $servicecomments{ $cid }{ 'comment_data' };

	#[<timestamp>] DEL_SVC_COMMENT;<comment_id>
	$nagios_cmd = sprintf "[%lu] DEL_SVC_COMMENT;%lu\n",
	    $now, $cid;

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


sub sort_servicecomments { 
    my( $r );
    $r = $servicecomments{$a}{'host'} cmp $servicecomments{$b}{'host'};
    return $r if ( $r != 0 );
    $r = $servicecomments{$a}{'service'} cmp $servicecomments{$b}{'service'};
    return $r;
    } 

