#!/usr/local/bin/perl -T # # cancel_downtime_matching.cgi # # wui to remove scheduled downtime # # by Doke Scott, doke at udel dot edu, 2014.8.14 # # $Header: /opt/home/doke/work/nagios/RCS/cancel_downtime_matching.cgi,v 1.1 2014/08/14 23:08:22 doke Exp $ # use strict; use warnings; use CGI qw/:standard -nosticky/; use Text::Glob qw( glob_to_regex ); use Date::Parse; use POSIX qw( strftime ); use vars qw( $statusfile $cmdfile $verbose $help $cgi $author %hosts %services_by_host ); $statusfile = "/usr/local/nagios/var/status.dat"; $cmdfile = "/usr/local/nagios/var/rw/nagios.cmd"; $verbose = 0; $help = 0; $author = $ENV{REMOTE_USER}; # get author's username from http basic auth $cgi = new CGI; $help = $cgi->param( 'help' ); print $cgi->header(), $cgi->start_html( -title => "nagios cancel downtime matching" ), "

nagios cancel downtime matching

\n"; print qq{ }; if ( $help == 1 ) { help(); } elsif ( ! $author ) { print "access denied\n" } else { main_form(); } print "

\n


\nUDel Network and Systems Services\n", $cgi->end_html(); exit 0; ################################### sub help { print qq{

This program cancels scheduled downtime for all nagios hosts and services that match a pattern. During scheduled downtime, nagios will not send out alerts about this host or service.

pattern

The pattern is compared with each hostname, each service name, and with "hostname/servicename". So if switch sw-ne37-110-1 has a ping service, the pattern will compared with 'sw-ne37-110-1', then 'ping', then 'sw-ne37-110-1/ping'.

The pattern uses standard unix glob wildcard syntax, except that it ignores case.
? matches any single character
* matches any number of any character, including zero characters
[abc] matches any of the characters in the brackets
[a-n] matches the range of characters in the brackets

Examples:
ups-* any host beginning with 'ups-', ie 'ups-ne37-117-1', 'ups-ne37-117-1/ping', or 'ups-ne37-117-1/liebert'
*ne37* anything with 'ne37' in the hostname or service, ie 'sw-ne37-110-1' or 'sw-ne37-110-1/ping'
*ping anything with 'ping' at the end of the hostname or service, ie 'sw-ne37-110-1/ping'

preview

The "preview" button will show you which host and service downtime the pattern would match, without actually doing anything. It's a very good idea to do this first.

really cancel downtime

The "really cancel downtime" button actually tells nagios to cancel the scheduled downtime.

effects

After canceling downtime, it will about 2 minutes for the change to show in nagios. It may take longer, expecially if nagios is busy, or you cancel downtime for a lot of things at once. }; } sub main_form { my( $progurl, $pattern, $pattern_re, $comment, $start, $start_esec, $duration, $end_esec, $preview, $really ); $progurl = "https://$ENV{HTTP_HOST}$ENV{SCRIPT_NAME}"; $pattern = $cgi->param( 'pattern' ); if ( ! defined $pattern ) { $pattern = ''; } print qq{

help
pattern:
}; $preview = $cgi->param( 'preview' ); $preview = ( defined $preview && $preview eq 'preview' ) ? 1 : 0; $really = $cgi->param( 'really cancel downtime' ); $really = ( defined $really && $really =~ m/really/i ) ? 1 : 0; if ( $preview || $really ) { print "

\n


\n

\n"; if ( ! defined $pattern || length( $pattern ) == 0 ) { print "you must enter a pattern\n"; return; } if ( $really ) { printf "really canceling downtime\n

\n"; } else { print "preview mode, not actually canceling downtime\n

\n"; } $Text::Glob::strict_wildcard_slash = 0; $pattern_re = glob_to_regex( lc $pattern ); $pattern_re =~ s/\?-xism/?i-xsm/; $verbose && print "pattern_re '$pattern_re'
\n"; read_statusfile( $pattern_re ); cancel_downtime_hosts( $really ); cancel_downtime_services( $really ); } } sub read_statusfile { my( $pattern ) = @_; my( $in_hostdowntime, $in_servicedowntime, $host, $service, $downtime_id, $current_state, $entry_time, $start_time, $end_time, $author, $comment ); open( fH, $statusfile ) || die "can't read-open $statusfile: $!\n"; $in_hostdowntime = 0; $in_servicedowntime = 0; $host = ''; $service = ''; $downtime_id = 0; $current_state = 0; $entry_time = 0; $start_time = 0; $end_time = 0; $author = ''; $comment = ''; while ( ) { if ( $in_servicedowntime || $in_hostdowntime ) { if ( m/^\s*host_name=(.*)/ ) { $host = $1; } elsif ( m/^\s*service_description=(.+)/ ) { $service = $1; } elsif ( m/^\s*downtime_id=(\d+)/ ) { $downtime_id = $1; } elsif ( m/^\s*current_state=(\d+)/ ) { $current_state = $1; } elsif ( m/^\s*entry_time=(\d+)/ ) { $entry_time = $1; } elsif ( m/^\s*start_time=(\d+)/ ) { $start_time = $1; } elsif ( m/^\s*end_time=(\d+)/ ) { $end_time = $1; } elsif ( m/^\s*author=(.+)/ ) { $author = $1; } elsif ( m/^\s*comment=(.+)/ ) { $comment = $1; } # { make vi happy elsif ( m/^\s*}\s*$/ ) { if ( $in_servicedowntime ) { if ( $host && $service && $downtime_id && ( $host =~ m/$pattern/i || $service =~ m/$pattern/i || "$host/$service" =~ m/$pattern/i ) ) { $verbose && print "found downtime for $host/$service\n"; $services_by_host{ $host }{ $service }{ 'downtime_id' } = $downtime_id; $services_by_host{ $host }{ $service }{ 'current_state' } = $current_state; $services_by_host{ $host }{ $service }{ 'entry_time' } = $entry_time; $services_by_host{ $host }{ $service }{ 'start_time' } = $start_time; $services_by_host{ $host }{ $service }{ 'end_time' } = $end_time; $services_by_host{ $host }{ $service }{ 'author' } = $author; $services_by_host{ $host }{ $service }{ 'comment' } = $comment; } $in_servicedowntime = 0; $host = ''; $service = ''; $downtime_id = 0; $current_state = 0; $entry_time = 0; $start_time = 0; $end_time = 0; $author = ''; $comment = ''; } elsif ( $in_hostdowntime ) { if ( $host && $downtime_id && $host =~ m/$pattern/i ) { $verbose && print "found downtime for $host\n"; $hosts{ $host }{ 'downtime_id' } = $downtime_id; $hosts{ $host }{ 'current_state' } = $current_state; $hosts{ $host }{ 'entry_time' } = $entry_time; $hosts{ $host }{ 'start_time' } = $start_time; $hosts{ $host }{ 'end_time' } = $end_time; $hosts{ $host }{ 'author' } = $author; $hosts{ $host }{ 'comment' } = $comment; } $in_hostdowntime = 0; $host = ''; $downtime_id = 0; $current_state = 0; $entry_time = 0; $start_time = 0; $end_time = 0; $author = ''; $comment = ''; } } } elsif ( m/^servicedowntime\s*{/ ) { # } make vi happy $in_servicedowntime = 1; $host = ''; $service = ''; $downtime_id = 0; $current_state = 0; $entry_time = 0; $start_time = 0; $end_time = 0; $author = ''; $comment = ''; } elsif ( m/^hostdowntime\s*{/ ) { # } make vi happy $in_hostdowntime = 1; $host = ''; $downtime_id = 0; $current_state = 0; $entry_time = 0; $start_time = 0; $end_time = 0; $author = ''; $comment = ''; } } close fH; } sub cancel_downtime_hosts { my( $really ) = @_; my( $now, $host, $nagios_cmd, $downtime_id ); print "

hosts:
\n"; if ( scalar( keys %hosts ) < 1 ) { print "no host downtime to cancel
\n"; return; } # append results to nagios command file if ( $really ) { if ( ! open( cH, ">$cmdfile" ) ) { print "error: can't write-open cmdfile $cmdfile: $!\n"; return; } } $now = time; print "\n"; foreach $host ( sort keys %hosts ) { printf "\n", $host, scalar( localtime( $hosts{ $host }{ 'start_time' } ) ), scalar( localtime( $hosts{ $host }{ 'end_time' } ) ), $hosts{ $host }{ 'author' }, $hosts{ $host }{ 'comment' }; $downtime_id = $hosts{ $host }{ 'downtime_id' }; $nagios_cmd = sprintf "[%lu] DEL_HOST_DOWNTIME;%u\n", $now, $downtime_id; $verbose && print "nagios_cmd = $nagios_cmd"; if ( $really ) { print cH $nagios_cmd; } } print "
%s%s%s%s%s
\n"; close cH; } sub cancel_downtime_services { my( $really ) = @_; my( $now, $host, $service, $nagios_cmd, $downtime_id ); print "

services:
\n"; if ( scalar( keys %services_by_host ) < 1 ) { print "no service downtime to cancel
\n"; return; } # append results to nagios command file if ( $really ) { if ( ! open( cH, ">$cmdfile" ) ) { print "error: can't write-open cmdfile $cmdfile: $!\n"; return; } } $now = time; print "\n"; foreach $host ( sort keys %services_by_host ) { foreach $service ( sort keys %{$services_by_host{ $host }} ) { printf "\n", $host, $service, scalar( localtime( $services_by_host{ $host }{ $service }{ 'start_time' } ) ), scalar( localtime( $services_by_host{ $host }{ $service }{ 'end_time' } ) ), $services_by_host{ $host }{ $service }{ 'author' }, $services_by_host{ $host }{ $service }{ 'comment' }; $downtime_id = $services_by_host{ $host }{ $service }{ 'downtime_id' }; $nagios_cmd = sprintf "[%lu] DEL_SVC_DOWNTIME;%u\n", $now, $downtime_id; $verbose && print "nagios_cmd = $nagios_cmd"; if ( $really ) { print cH $nagios_cmd; } } } print "
%s/%s%s%s%s%s
\n"; close cH; }