#!/usr/bin/perl -T # # monshow - concise, user view-based opstatus summary # # Jim Trocki, trockij@transmeta.com # # Modified to produce WAP (wml) output by # Dobrica Pavlinusic # http://www.rot13.org/~dpavlin/sysadm.html # # Since it uses ... tags in wml outout, this script will NOT WORK # on Nokia 7110. # # $Id: monshow 1.7 Sun, 24 Jun 2001 22:41:40 -0400 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 # use strict "vars"; use Getopt::Long; use English; use CGI; use Text::Wrap; use Mon::Client; use Data::Dumper; my $warn_re = qq{(news/nntp|.*ping)}; # # 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 pre_pad_if_empty; sub tdiff_string; # # set this to the path of your view configuration files # my $VIEWPATH = "/etc/mon/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; # safe $PATH for taint mode $ENV{PATH} = '/usr/local/bin:/usr/bin:/bin'; my ($DEP, $GROUP, $SERVICE, $STATUS, $TIME, $NEXT, $ALERTS, $SUMMARY, $DESC); # Untaint args, tainting is just for stuff which comes from CGI. for (@ARGV) { /(.*)/s or die; $_ = $1; } my %opt; GetOptions (\%opt, "showall", "auth", "help", "full", "disabled", "rcfile=s", "login=s", "server=s", "port=i", "prot=s", "detail=s", "view=s") || usage; @ARGV == 0 || usage "No non-switch args expected\n"; my $CGI; my %QUERY_ARGS; if (defined $ENV{"REQUEST_METHOD"}) { unless ($CGI = new CGI) { $CGI = 1; err_die ("Can't create CGI object\n"); } } if (!$CGI && $opt{"help"}) { usage; } my $WAP = 0; if ($CGI) { print STDERR "monshow: text/vnd.wap.wml: ",$CGI->Accept('text/vnd.wap.wml'), " text/html: ",$CGI->Accept('text/html')," ",$CGI->user_agent,"\n"; $WAP = 1 if ($CGI->Accept('text/vnd.wap.wml') >= $CGI->Accept('text/html') && ! $CGI->user_agent('MSIE')); foreach my $e (split (/\?/, $ENV{"QUERY_STRING"})) { next if ($e !~ /=/); my ($var, $val) = split (/=/, $e); $QUERY_ARGS{$var} = $val; } } my $CF = { "host" => "localhost", "full" => 0, "show-disabled" => 0, "bg" => "d5d5d5", "bg-ok" => "a0d0a0", "bg-fail" => "e088b7", "bg-warn" => "d0d080", "bg-untested" => "e0e0e0", "table-color" => "cccccc", "summary-len" => 20, }; 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 ($WAP) { 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 = "/etc/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-untested") { } elsif ($cmd eq "table-color") { } elsif ($cmd eq "html-header") { $html_header = 1; next; } elsif ($cmd eq "refresh") { } elsif ($cmd eq "summary-len") { } 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 ($WAP) { print <

$msg

EOF } elsif ($CGI) { print < Error

Error

$msg
EOF } else { print < All systems OK

EOF $OUT_BUF .= " All systems OK " if ($WAP); } 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 ne "") { 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"; } grep {s/\*//} @g; $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 $OUT_BUF = < EOF if ($CF->{"refresh"}) { $OUT_BUF .= < {refresh}> EOF } $OUT_BUF .= < EOF if ($CF->{"html-header"} ne "") { $OUT_BUF .= $CF->{"html-header"} if (! $WAP); } $OUT_BUF .= <Operational Status EOF } my @wml; foreach my $l (@{$rows}) { my ($depstate, $group, $service) = @{$l}; my $sref = \%{$st->{"opstatus"}->{$group}->{$service}}; $STATUS = "unknown"; $TIME = ""; $DEP = $depstate; my $last = ""; my $opstatus = $sref->{"opstatus"}; my $bgcolor = opstatus_color ($opstatus); if ($opstatus == $OPSTAT{"untested"}) { $STATUS = "untested"; $TIME = "untested"; } elsif ($opstatus == $OPSTAT{"ok"}) { $STATUS = "-"; } elsif ($opstatus == $OPSTAT{"fail"}) { if ($sref->{"ack"}) { if ($CGI) { $STATUS = "" . "ACK FAIL"; } else { $STATUS = "ACK FAIL"; } } else { $STATUS = "FAIL"; } } if ($opstatus == $OPSTAT{"fail"} && "$group/$service" =~ /$warn_re/i) { $bgcolor = $CF->{"bg-warn"}; $STATUS = "WARN"; } if ($depstate eq "") { $DEP = "-"; } $GROUP = $group; $SERVICE = $service; $DESC = $st->{"desc"}->{$group}->{$service}; $DESC = pre_pad_if_empty ($DESC) if ($CGI); if ($TIME eq "") { $TIME = tdiff_string (time - $sref->{"last_check"}); } if ($sref->{"timer"} < 60) { $NEXT = "$sref->{timer}s"; } else { $NEXT = secs_to_hms ($sref->{"timer"}); } if (length ($sref->{"last_summary"}) > $CF->{"summary-len"}) { $SUMMARY = substr ($sref->{"last_summary"}, 0, $CF->{"summary-len"}) . "..."; } else { $SUMMARY = $sref->{"last_summary"}; } $ALERTS = $sref->{"alerts_sent"} || "none"; my $fmt; if (!$CGI) { $fmt = < EOF # dump just failuers to wap mobile if ($WAP) { if ($sref->{"opstatus"} == $OPSTAT{"fail"}) { push @wml,< $GROUP $SERVICE $TIME/$NEXT $STATUS $SUMMARY

EOF } else { push @wml,< $GROUP $SERVICE

EOF } } } } if ($CGI) { $OUT_BUF .= < EOF # generate page-by-page output my $on_page=10; my $max_page=int(($#wml + $on_page) / $on_page) - 1; if ($WAP) { my $p = $QUERY_ARGS{"p"} || 1; # current page $OUT_BUF .= ""; for (my $i = 0; $i < $on_page; $i++) { $OUT_BUF .= $wml[$i + ($p-1) * $on_page]; } # navigation $OUT_BUF .= "

"; for (my $i = 1; $i <= $max_page; $i++) { if ($i == $p) { $OUT_BUF .= "$i "; } else { $OUT_BUF .= "$i "; } } $OUT_BUF .= "

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

" if (! $WAP); } else { print "\nNothing is disabled.\n"; } return; } if (keys %{$disabled->{"watches"}}) { if ($CGI) { $OUT_BUF .= < Disabled Watches EOF $OUT_BUF .= " Disabled Watches " if ($WAP); } else { print "\nDISABLED WATCHES:\n"; } foreach my $watch (keys %{$disabled->{"watches"}}) { if ($CGI) { $OUT_BUF .= "$watch
\n"; } else { print "$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 .= < Disabled Services EOF $OUT_BUF .= " Disabled Services " if ($WAP); } else { print "\nDISABLED SERVICES\n"; } for (@disabled_services) { if ($CGI) { $OUT_BUF .= "$_
\n"; } else { print "$_\n"; } } } if (keys %{$disabled->{"hosts"}}) { if ($CGI) { $OUT_BUF .= < Disabled Hosts EOF $OUT_BUF .= < Disabled Hosts

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) { $OUT_BUF .= sprintf ("%-15s %s
\n", $group, "@HOSTS"); } else { printf ("%-15s %s\n", $group, "@HOSTS"); } } } } sub compose_trailer { if ($CGI) { $OUT_BUF .= < EOF $OUT_BUF .= < EOF } } sub compose_detail { my ($args, $st) = @_; my ($group, $service, $optarg) = split (/,/, $args, 3); 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"}); if ($sref->{"opstatus"} == $OPSTAT{"fail"} && "$group/$service" =~ /$warn_re/i) { $bgcolor = $CF->{"bg-warn"}; } $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 && !$WAP && $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) { my $sum = pre_pad_if_empty ($sref->{"last_summary"}); my $descr = pre_pad_if_empty ($st->{"desc"}->{$group}->{$service}); my $hosts = pre_pad_if_empty ("@{$st->{groups}->{$group}}"); $OUT_BUF .= <Detail for $group/$service
EOF # skip overview card if detail page is used or next page navigation $OUT_BUF .= <

Server: $CF->{host}
Time: $t
State: $state

Display status

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


--> 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 .= <
Dep Group Service Desc. Last check Next check Alerts Status Summary
$DEP $GROUP $SERVICE $DESC $TIME $NEXT $ALERTS $STATUS $SUMMARY
Description: $descr
Summary: $sum
Hosts: $hosts
Detail:
$sref->{last_detail}
	
EOF my $wml = <Description: $descr

Summary: $sum

Hosts: $hosts

Detail: EOF my $wml_detail = "no detail -- bug!"; if ($WAP) { if ($optarg eq "full") { $wml_detail = $sref->{last_detail}; } elsif (length $sref->{last_detail} > 200) { $wml .= substr($sref->{last_detail},0,200) . "... [more]"; } else { $wml .= $sref->{last_detail}; } } $wml .= "

"; if ($d->{"ack"}) { my $comment = pre_pad_if_empty ($d->{"ackcomment"}); $OUT_BUF .= <

Acknowledgment of failure

$comment EOF $wml .= <Acknowledgment of failure: $comment

EOF } $OUT_BUF .= < EOF $wml .= < 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], ["timer", "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 EOF $wml .= "
$k->[1]: $$v" if ($WAP); } $OUT_BUF .= < EOF $wml .= < 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 $wml .= < {links}->{$group}->{$service}->{link}\">More Information $CF->{links}->{$group}->{$service}->{'link-text'}

EOF } else { $OUT_BUF .= < $CF->{links}->{$group}->{$service}->{link} EOF $wml .= < $CF->{links}->{$group}->{$service}->{link}

EOF } } $OUT_BUF .= < Back to summary table

EOF # dump out wml if ($optarg eq "full") { $wml_detail =~ s/[\n\r]+//g; $wml = "

$wml_detail

"; } $OUT_BUF .= < $wml 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}s"; } 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); } } } sub pre_pad_if_empty { my $l = shift; return "
 
" if ($l =~ /^\s*$/ && !$WAP); $l; }