#!/usr/local/bin/perl # # modified to customize for this webmin module of MON-dt 09th sept 2001 # monshow - concise, user view-based opstatus summary # # Jim Trocki, trockij@transmeta.com # # $Id: monshow 1.1 Sat, 26 Aug 2000 12:22:34 -0700 trockij $ # # Copyright (C) 1998, Jim Trocki # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # require './mon-lib.pl'; &init_config(); &ui_print_header(undef, $text{'mon_status_title'}, "","monshow"); print "
\n"; use strict "vars"; use Getopt::Long; use English; use CGI; use Text::Wrap; use Mon::Client; use Data::Dumper; # # forward declarations # sub usage; sub get_auth; sub read_cf; sub err_die; sub expand_watch; sub secs_to_hms; sub display_allok; sub compose_detail; sub compose_header; sub compose_disabled; sub compose_table; sub compose_trailer; sub get_client_status; sub opstatus_color; sub tdiff_string; # # set this to the path of your view configuration files # my $VIEWPATH = "/etc/mon/monshow"; #my $VIEWPATH = "/home/trockij/monshow"; my %OPSTAT = %Mon::Client::OPSTAT; my $WORD = '[a-zA-Z0-9_-]+'; my $OUT_BUF = ""; my $e; $= = 1000; $SIG{INT} = \&handle_sig; $SIG{TERM} = \&handle_sig; my ($DEP, $GROUP, $SERVICE, $STATUS, $TIME, $NEXT, $ALERTS, $SUMMARY, $DESC); my %opt; GetOptions (\%opt, "showall", "auth", "help", "full", "disabled", "rcfile=s", "login=s", "server=s", "port=i", "prot=s", "detail=s", "view=s"); my $CGI; my %QUERY_ARGS; if (defined $ENV{"REQUEST_METHOD"}) { $CGI = new CGI; } if (!$CGI && $opt{"help"}) { usage; exit 1; } if ($CGI) { foreach my $e (split (/\?/, $ENV{"QUERY_STRING"})) { next if ($e !~ /=/); my ($var, $val) = split (/=/, $e); $QUERY_ARGS{$var} = $val; } } my $CF = { "full" => 0, "show-disabled" => 0, "bg" => "d5d5d5", "bg-ok" => "a0d0a0", "bg-fail" => "FF66FF", "bg-disabled" => "FAEBD7", "bg-untested" => "e0e0e0", "table-color" => "cccccc", }; my $GLOBAL = { "view-name" => undef, }; # # read config file # my ($e, $what) = read_cf ($CF); if ($e ne "") { err_die ("while reading config file, $e"); } # # cmdline args override config file # if (!$CGI) { $CF->{"all"} = 1 if ($opt{"showall"}); $CF->{"full"} = 1 if ($opt{"full"}); $CF->{"detail"} = $opt{"detail"} if ($opt{"detail"} ne ""); $CF->{"host"} = $opt{"server"} if ($opt{"server"}); $CF->{"port"} = $opt{"port"} if ($opt{"port"}); $CF->{"prot"} = $opt{"prot"} if ($opt{"prot"}); } # # retrieve client status # my ($e, $st) = get_client_status ($what); if ($e ne "") { err_die ($e); } expand_watch ($what, $st); my $rows = select_table ($what, $st); compose_header ($st->{"state"}); # # CGI invocation # if ($CGI) { if ($QUERY_ARGS{"disabled"}) { compose_disabled ($st->{"disabled"}); } elsif (!$QUERY_ARGS{"detail"}) { compose_table ($rows, $st); compose_disabled ($st->{"disabled"}) if ($CF->{"show-disabled"}); } elsif ($QUERY_ARGS{"detail"}) { compose_detail ($QUERY_ARGS{"detail"}, $st); } } # # cmdline invocation # else { if ($opt{"disabled"}) { compose_disabled ($st->{"disabled"}); } elsif ($CF->{"detail"} ne "") { compose_detail ($CF->{"detail"}, $st); } else { compose_table ($rows, $st); compose_disabled ($st->{"disabled"}) if ($CF->{"show-disabled"}); } } compose_trailer; if ($CGI) { #Content-type: text/html print <

EOF &footer("./","MON Index page"); } else { print "\n"; } exit; #----------------------------------------------------------------------------- format STDOUT_TOP = GROUP SERVICE STATUS LAST NEXT ALERTS SUMMARY . # # usage # sub usage { print <query ("login"); $pass = $CGI->query ("password"); } else { if ($opt{"login"}) { $login = $opt{"login"}; } else { return "could not determine username" if (!defined ($login = getpwuid($EUID))); } if (-t STDIN) { system "stty -echo"; print "Password: "; chop ($pass = ); print "\n"; system "stty echo"; return "invalid password" if ($pass =~ /^\s*$/); } else { my $cmd; while (defined ($cmd = <>)) { chomp $cmd; if ($cmd =~ /^user=(\S+)$/i) { $login = $1; } elsif ($cmd =~ /^pass=(\S+)$/i) { $pass = $1; } last if (defined ($login) && defined ($pass)); } } } return "inadequate authentication information supplied" if ($login eq "" || $pass eq ""); return ("", $login, $pass); } # # config file # sub read_cf { my $CF = shift; my ($group, $service); my @RC; my $view = 0; my $RC = "/webmin-0.87/mon/monshowrc"; if ($CGI) { if ($ENV{"PATH_INFO"} =~ /^\/\S+/) { my $p=$ENV{"PATH_INFO"}; $p =~ s/^[.\/]*//; $p =~ s/\/*$//; $p =~ s/\.\.//g; $RC = "$VIEWPATH/$p"; $GLOBAL->{"view-name"} = $p; $view = 1; } elsif ($QUERY_ARGS{"view"} ne "") { $QUERY_ARGS{"view"} =~ s/^[.\/]*//; $QUERY_ARGS{"view"} =~ s/\.\.//g; $GLOBAL->{"view-name"} = $QUERY_ARGS{"view"}; $RC = "$VIEWPATH/$QUERY_ARGS{view}"; $view = 1; } elsif (-f ".monshowrc") { $RC = ".monshowrc"; } } else { if ($opt{"rcfile"}) { $RC = $opt{"rcfile"}; } elsif ($opt{"view"} ne "") { $RC = "$VIEWPATH/$opt{view}"; $GLOBAL->{"view-name"} = $opt{"view"}; $view = 1; } elsif (-f "$ENV{HOME}/.monshowrc") { $RC = "$ENV{HOME}/.monshowrc"; } } if ($opt{"old"}) { $CF->{"prot"} = "0.37.0"; $CF->{"port"} = 32777; } if (-f $RC) { open (IN, $RC) || return "could not read $RC: $!"; my $html_header = 0; my $link_text = 0; my $link_group = ""; my $link_service = ""; while () { next if (/^\s*#/ || /^\s*$/); if ($html_header) { if (/^END\s*$/) { $html_header = 0; next; } else { $CF->{"html-header"} .= $_; next; } } elsif ($link_text) { if (/^END\s*$/) { $link_text = 0; next; } else { $CF->{"links"}->{$link_group}->{$link_service}->{"link-text"} .= $_; next; } } else { chomp; s/^\s*//; s/\s*$//; } if (/^set \s+ (\S+) \s* (\S+)?/ix) { my $cmd = $1; my $arg = $2; if ($cmd eq "show-disabled") { } elsif ($cmd eq "host") { } elsif ($cmd eq "prot") { } elsif ($cmd eq "port") { } elsif ($cmd eq "full") { } elsif ($cmd eq "bg") { } elsif ($cmd eq "bg-ok") { } elsif ($cmd eq "bg-fail") { } elsif ($cmd eq "bg-disabled") { } elsif ($cmd eq "bg-untested") { } elsif ($cmd eq "table-color") { } elsif ($cmd eq "html-header") { $html_header = 1; next; } elsif ($cmd eq "refresh") { } else { print STDERR "unknown set, line $.\n"; next; } if ($arg ne "") { $CF->{$cmd} = $arg; } else { $CF->{$cmd} = 1; } } elsif (/^watch \s+ (\S+)/x) { push (@RC, [$1]); } elsif (/^service \s+ (\S+) \s+ (\S+)/x) { push (@RC, [$1, $2]); } elsif (/^link \s+ (\S+) \s+ (\S+) \s+ (.*)\s*/ix) { $CF->{"links"}->{$1}->{$2}->{"link"} = $3; } elsif (/^link-text \s+ (\S+) \s+ (\S+)/ix) { $link_text = 1; $link_group = $1; $link_service = $2; next; } else { my $lnum = $.; close (IN); err_die ("error in config file, line $."); } } close (IN); } elsif (! -f $RC && $view) { err_die ("no view found"); } return ("", \@RC); } sub secs_to_hms { my ($s) = @_; my ($dd, $hh, $mm, $ss); $dd = int ($s / 86400); $s -= $dd * 86400; $hh = int ($s / 3600); $s -= $hh * 3600; $mm = int ($s / 60); $s -= $mm * 60; $ss = $s; if ($dd == 0) { sprintf("%02d:%02d", $hh, $mm); } else { sprintf("%d days, %02d:%02d", $dd, $hh, $mm); } } # # exit displaying error in appropriate output format # sub err_die { my $msg = shift; if ($CGI) { print < Error

Error

$msg
EOF } else { print < All systems OK

EOF } else { print "\nAll systems OK\n"; } } # # client status # # return ("", $state, \%opstatus, \%disabled, \%deps, \%groups, \%descriptions); # sub get_client_status { my $what = shift; my $cl; if (!defined ($cl = Mon::Client->new)) { return "could not create client object: $@"; } my ($username, $pass); if ($opt{"auth"} && !$CGI) { my $e; ($e, $username, $pass) = get_auth; if ($e eq "") { return "$e"; } $cl->username ($username); $cl->password ($pass); } $cl->host ($CF->{"host"}) if (defined $CF->{"host"}); $cl->port ($CF->{"port"}) if (defined $CF->{"port"}); $cl->port ($CF->{"prot"}) if (defined $CF->{"prot"}); $cl->connect; if ($cl->error) { return "Could not connect to server: " . $cl->error; } # # authenticate self to the server if necessary # if ($opt{"auth"} && !defined ($cl->login)) { my $e = $cl->error; $cl->disconnect; return "Could authenticate: $e"; } # # get disabled things # my %disabled = $cl->list_disabled; if ($cl->error) { my $e = $cl->error; $cl->disconnect; return "could not get disabled: $e"; } # # get state # my ($running, $t) = $cl->list_state; if ($cl->error) { my $e = $cl->error; $cl->disconnect; return "could not get state: $e"; } my $state; if ($running) { $state = $t; } else { $state = "scheduler stopped since " . localtime ($t); } # # group/service list # my @watch = $cl->list_watch; if ($cl->error) { my $e = $cl->error; $cl->disconnect; return "could not get opstatus: $e"; } # # get opstatus # my %opstatus; if (@{$what} == 0) { %opstatus = $cl->list_opstatus; if ($cl->error) { my $e = $cl->error; $cl->disconnect; return "could not get opstatus: $e"; } } else { my @list; foreach my $r (@{$what}) { if (@{$r} == 2) { push @list, $r; } else { foreach my $w (@watch) { next if ($r->[0] ne $w->[0]); push @list, $w; } } } %opstatus = $cl->list_opstatus (@list); if ($cl->error) { my $e = $cl->error; $cl->disconnect; return "could not get opstatus: $e"; } } # # dependencies # my %deps; if ($opt{"deps"}) { %deps = $cl->list_deps; if ($cl->error) { my $e = $cl->error; $cl->disconnect; return "could not list deps: $e"; } } # # descriptions # my %desc; %desc = $cl->list_descriptions; if ($cl->error) { my $e = $cl->error; $cl->disconnect; return "could not list descriptions: $e"; } # # groups # my %groups; if ($QUERY_ARGS{"detail"} || $CF->{"detail"} ne "") { foreach my $g (keys %opstatus) { my @g = $cl->list_group ($g); if ($cl->error) { my $e = $cl->error; $cl->disconnect; return "could not list group: $e"; } $groups{$g} = [@g]; } } # # log out # if (!defined $cl->disconnect) { return "error while disconnecting: " . $cl->error; } return ("", { "state" => $state, "opstatus" => \%opstatus, "disabled" => \%disabled, "deps" => \%deps, "groups" => \%groups, "desc" => \%desc, "watch" => \@watch, }); } sub compose_header { my $state = shift; my $t = localtime; # # HTML stuff # if ($CGI) { $OUT_BUF = < Operational Status EOF if ($CF->{"refresh"}) { $OUT_BUF .= < {refresh}> EOF } $OUT_BUF .= "\n"; if ($CF->{"html-header"} ne "") { $OUT_BUF .= $CF->{"html-header"}; } $OUT_BUF .= < {'table-color'}> EOF } $OUT_BUF .= < EOF # # custom links # if (defined ($CF->{"links"}->{$group}->{$service})) { if (defined ($CF->{"links"}->{$group}->{$service}->{"link-text"})) { $OUT_BUF .= <

{links}->{$group}->{$service}->{link}\">More Information

$CF->{links}->{$group}->{$service}->{'link-text'} EOF } else { $OUT_BUF .= < $CF->{links}->{$group}->{$service}->{link} EOF } } $OUT_BUF .= <
Back to summary table

EOF } # # text output # else { my $n; $Text::Wrap::columns = 70; $n->{"desc"} = wrap (" ", " ", $st->{"desc"}->{$group}->{$service}); $n->{"last_summary"} = wrap (" ", " ", $sref->{"last_summary"}); $n->{"hosts"} = wrap (" ", " ", join (" ", @{$st->{groups}->{$group}})); print <{desc} summary ------- $n->{last_summary} hosts ----- $n->{hosts} -----DETAIL----- $sref->{last_detail} -----DETAIL----- EOF if ($d->{"ack"}) { print <{ackcomment} EOF } print <{opstatus} exitval: $d->{exitval} depend: $d->{depend} monitor: $d->{monitor} last check: $d->{last_check} next_check: $d->{timer} EOF } } sub opstatus_color { my $o = shift; my %color_hash = ( $OPSTAT{"untested"} => $CF->{"bg-untested"}, $OPSTAT{"ok"} => $CF->{"bg-ok"}, $OPSTAT{"fail"} => $CF->{"bg-fail"}, ); $color_hash{$o} || ""; } sub tdiff_string { my $time = shift; my $s; if ($time <= 90) { $s = "$time secs"; } else { $s = secs_to_hms ($time); } } # # for each watch entry which specifies only "group", # expand it into "group service" # sub expand_watch { my $what = shift; my $st = shift; for (my $i=0; $i<@{$what}; $i++) { if (@{$what->[$i]} == 1) { my @list; foreach my $l (@{$st->{"watch"}}) { if ($l->[0] eq $what->[$i]->[0]) { push @list, $l; } } splice (@{$what}, $i, 1, @list); } } }

EOF if ($GLOBAL->{"view-name"} ne "") { $OUT_BUF .= < EOF } $OUT_BUF .= <
Server: $CF->{host}
Time: $t
State: $state
View: $GLOBAL->{"view-name"}
Color legend
all is OK failure untested disabled


EOF } else { print <{host} time: $t state: $state EOF } } sub select_table { my ($what, $st) = @_; my @rows; # # display everything real nice # if ($CF->{"all"} || @{$what} == 0) { foreach my $group (keys %{$st->{"opstatus"}}) { foreach my $service (keys %{$st->{"opstatus"}->{$group}}) { push (@rows, [$group, $service]); } } } else { @rows = @{$what}; } my (%DEP, %DEPROOT); foreach my $l (@rows) { my ($group, $service) = @{$l}; my $sref = \%{$st->{"opstatus"}->{$group}->{$service}}; next if (!defined $sref->{"opstatus"}); # # disabled things # # fuckin' Perl, man. Just be referencing # $st->{"disabled"}->{"watches"}->{$group}, perl automagically # defines that hash element for you. Great. # if (defined ($st->{"disabled"}->{"watches"}) && defined ($st->{"disabled"}->{"watches"}->{$group})) { next; } elsif (defined ($st->{"disabled"}->{"services"}) && defined ($st->{"disabled"}->{"services"}->{$group}) && defined ($st->{"disabled"}->{"services"}->{$service})) { next; } # # potential root dependencies # elsif ($sref->{"depend"} eq "") { push (@{$DEPROOT{$sref->{"opstatus"}}}, ["R", $group, $service]); } # # things which have dependencies # else { push (@{$DEP{$sref->{"opstatus"}}}, ["D", $group, $service]); } } if ($CF->{"full"}) { [ @{$DEPROOT{$OPSTAT{"fail"}}}, @{$DEPROOT{$OPSTAT{"linkdown"}}}, @{$DEPROOT{$OPSTAT{"timeout"}}}, @{$DEPROOT{$OPSTAT{"coldstart"}}}, @{$DEPROOT{$OPSTAT{"warmstart"}}}, @{$DEPROOT{$OPSTAT{"untested"}}}, @{$DEPROOT{$OPSTAT{"unknown"}}}, @{$DEP{$OPSTAT{"fail"}}}, @{$DEP{$OPSTAT{"linkdown"}}}, @{$DEP{$OPSTAT{"timeout"}}}, @{$DEP{$OPSTAT{"coldstart"}}}, @{$DEP{$OPSTAT{"warmstart"}}}, @{$DEPROOT{$OPSTAT{"ok"}}}, @{$DEP{$OPSTAT{"ok"}}}, @{$DEP{$OPSTAT{"untested"}}}, @{$DEP{$OPSTAT{"unknown"}}}, ]; } else { [ @{$DEPROOT{$OPSTAT{"fail"}}}, @{$DEPROOT{$OPSTAT{"linkdown"}}}, @{$DEPROOT{$OPSTAT{"timeout"}}}, @{$DEPROOT{$OPSTAT{"coldstart"}}}, @{$DEPROOT{$OPSTAT{"warmstart"}}}, @{$DEP{$OPSTAT{"fail"}}}, @{$DEP{$OPSTAT{"linkdown"}}}, @{$DEP{$OPSTAT{"timeout"}}}, @{$DEP{$OPSTAT{"coldstart"}}}, @{$DEP{$OPSTAT{"warmstart"}}}, ]; } } # # build the table # sub compose_table { my ($rows, $st) = @_; if (@{$rows} == 0) { display_allok; return; } # # display the failure table # if ($CGI) { $OUT_BUF .= <

Full View (To Disable / View Details, Click on the link under Service column)
Depends Group Service Desc. Last check Next check Alerts Status Summary EOF } foreach my $l (@{$rows}) { my ($depstate, $group, $service) = @{$l}; my $sref = \%{$st->{"opstatus"}->{$group}->{$service}}; $STATUS = "unknown"; $TIME = ""; $DEP = $depstate; my $last = ""; my $bgcolor = opstatus_color ($sref->{"opstatus"}); if ($sref->{"opstatus"} == $OPSTAT{"untested"}) { $STATUS = "untested"; $TIME = "untested"; } elsif ($sref->{"opstatus"} == $OPSTAT{"ok"}) { $STATUS = "-"; } elsif ($sref->{"opstatus"} == $OPSTAT{"fail"}) { if ($sref->{"ack"}) { if ($CGI) { $STATUS = "" . "ACK FAIL"; } else { $STATUS = "ACK FAIL"; } } else { $STATUS = "FAIL"; } } if ($depstate eq "") { $DEP = "-"; } $GROUP = $group; $SERVICE = $service; $DESC = $st->{"desc"}->{$group}->{$service}." "; if ($TIME eq "") { $TIME = tdiff_string (time - $sref->{"last_check"}) . " ago"; } if ($sref->{"timer"} < 60) { $NEXT = "$sref->{timer} secs"; } else { $NEXT = secs_to_hms ($sref->{"timer"}); } $SUMMARY = $sref->{"last_summary"}; $ALERTS = $sref->{"alerts_sent"} || "none"; my $fmt; if (!$CGI) { $fmt = < $DEP $GROUP $SERVICE $DESC $TIME $NEXT $ALERTS $STATUS $SUMMARY EOF } } if ($CGI) { $OUT_BUF .= <

Disabled Hosts/Watch/Services
EOF } } sub compose_disabled { my $disabled = shift; if (!keys %{$disabled->{"watches"}} && !keys %{$disabled->{"services"}} && !keys %{$disabled->{"hosts"}}) { if ($CGI) { $OUT_BUF .= <
Nothing is disabled

EOF } else { print "\nNothing is disabled.\n"; } return; } if (keys %{$disabled->{"watches"}}) { if ($CGI) { $OUT_BUF .= <

EOF } else { print "\nDISABLED WATCHES:\n"; } foreach my $watch (keys %{$disabled->{"watches"}}) { if ($CGI) { $OUT_BUF .= "{'bg-disabled'}>\n"; } else { print "$watch\n"; } } if ($CGI) { $OUT_BUF .= "
Disabled WatchesClick Link to Enable Desired Watch
$watchEnable Watch
\n"; } } my @disabled_services; foreach my $watch (keys %{$disabled->{"services"}}) { foreach my $service (keys %{$disabled->{"services"}{$watch}}) { push (@disabled_services, "$watch $service");; } } if (@disabled_services) { if ($CGI) { $OUT_BUF .= <
EOF } else { print "\nDISABLED SERVICES\n"; } for (@disabled_services) { if ($CGI) { my $aaa=$_; $aaa=~s/\s+/ -> /; $OUT_BUF .= "{'bg-disabled'}>\n"; } else { print "$_\n"; } } if ($CGI) { $OUT_BUF .= "
Disabled Services (Hostgroup -> Service) Click Link to Enable Desired Service
$aaaEnable Service
\n"; } } if (keys %{$disabled->{"hosts"}}) { if ($CGI) { $OUT_BUF .= <
EOF } else { print "\nDISABLED HOSTS:\n"; } foreach my $group (keys %{$disabled->{"hosts"}}) { my @HOSTS = (); foreach my $host (keys %{$disabled->{"hosts"}{$group}}) { push (@HOSTS, $host); } if ($CGI) { foreach my $sdd(@HOSTS){ $OUT_BUF .= sprintf ("{'bg-disabled'}>\n", $group, $sdd); } } else { printf ("%-15s %s\n", $group, "@HOSTS"); } } if ($CGI) { $OUT_BUF .= "
Disabled Hosts (Hostgroup -> Host)Click Link to Enable Desired Host
%-15s -> %s Enable Host
\n"; } } } sub compose_trailer { if ($CGI) { $OUT_BUF .= < EOF } } sub compose_detail { my ($args, $st) = @_; my ($group, $service) = split (/,/, $args, 2); if (!defined ($st->{"opstatus"}->{$group}->{$service})) { err_die ("$group/$service not a valid service"); } my $sref = \%{$st->{"opstatus"}->{$group}->{$service}}; my $d; my $bgcolor = opstatus_color ($sref->{"opstatus"}); $bgcolor = "bgcolor='#$bgcolor'" if ($bgcolor ne ""); foreach my $k (keys %OPSTAT) { if ($OPSTAT{$k} == $sref->{"opstatus"}) { $sref->{"opstatus"} = "$k ($sref->{opstatus})"; last; } } foreach my $k (qw (opstatus exitval last_check timer ack ackcomment)) { if ($CGI && $sref->{$k} =~ /^\s*$/) { $d->{$k} = "
 
"; } else { $d->{$k} = $sref->{$k}; } } my $t = time; $d->{"last_check"} = tdiff_string ($t - $d->{"last_check"}) . " ago"; $d->{"timer"} = "in " . tdiff_string ($d->{"timer"}); foreach my $k (qw (last_success last_failure first_failure last_alert)) { if ($sref->{$k}) { $d->{$k} = localtime ($sref->{$k}); } } if ($sref->{"first_failure"}) { $d->{"failure_duration"} = secs_to_hms ($sref->{"failure_duration"}); } # # HTML output # if ($CGI) { $OUT_BUF .= <
Detail for $group/$service(Click the link to Disable Watch/Service/Hosts )
Description: $st->{desc}->{$group}->{$service} Disable Service
Summary: $sref->{last_summary}  
Hosts: @{$st->{groups}->{$group}}      (Note: * indicates disabled host) EOF foreach $_(@{$st->{groups}->{$group}}){ $OUT_BUF .= sprintf ("%s Disable Host: $_
"); } $OUT_BUF .= <
Detail:  
$sref->{last_detail}
	
Disable Watch
EOF if ($d->{"ack"}){ $OUT_BUF .= <

Acknowledgment of failure

$d->{ackcomment}
EOF } $OUT_BUF .= < EOF # # 0 = nothing special # 1 = do not display if zero # 2 = do not display if eq "" # foreach my $k ( ["opstatus", "Operational Status", 0], ["exitval", "Exit Value", 0], ["depend", "Dependency", 2], ["monitor", "Monitor Program", 2], ["last_check", "Last Check", 2], ["next_check", "Next Check", 2], ["last_success", "Last Success", 2], ["last_failure", "Last Failure", 2], ["first_failure", "First Failure", 2], ["failure_duration", "Failure Duration", 2], ["interval", "Schedule Interval", 0], ["exclude_period", "Exclude Period", 2], ["exclude_hosts", "Exclude Hosts", 2], ["randskew", "Random Skew", 1], ["alerts_sent", "Alerts Sent", 1], ["last_alert", "Last Alert", 2]) { my $v = undef; if ($d->{$k->[0]} ne "") { $v = \$d->{$k->[0]}; } elsif ($sref->{$k->[0]} ne "") { $v = \$sref->{$k->[0]}; } next if ($k->[2] == 1 && $$v == 0); next if ($k->[2] == 2 && $$v eq ""); $OUT_BUF .= <
$k->[1]: $$v