/[mon-modules]/monshow.cgi
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /monshow.cgi

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (show annotations)
Sat Aug 10 16:33:09 2002 UTC (16 years, 11 months ago) by dpavlin
Branch: MAIN
import of monshow 1.7

1 #!/usr/bin/perl -T
2 #
3 # monshow - concise, user view-based opstatus summary
4 #
5 # Jim Trocki, trockij@transmeta.com
6 #
7 # $Id: monshow 1.7 Sun, 24 Jun 2001 22:41:40 -0400 trockij $
8 #
9 # Copyright (C) 1998, Jim Trocki
10 #
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 2 of the License, or
14 # (at your option) any later version.
15 #
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
20 #
21 # You should have received a copy of the GNU General Public License
22 # along with this program; if not, write to the Free Software
23 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #
25 use strict "vars";
26
27 use Getopt::Long;
28 use English;
29 use CGI;
30 use Text::Wrap;
31 use Mon::Client;
32 use Data::Dumper;
33
34 #
35 # forward declarations
36 #
37 sub usage;
38 sub get_auth;
39 sub read_cf;
40 sub err_die;
41 sub expand_watch;
42 sub secs_to_hms;
43 sub display_allok;
44 sub compose_detail;
45 sub compose_header;
46 sub compose_disabled;
47 sub compose_table;
48 sub compose_trailer;
49 sub get_client_status;
50 sub opstatus_color;
51 sub pre_pad_if_empty;
52 sub tdiff_string;
53
54 #
55 # set this to the path of your view configuration files
56 #
57 my $VIEWPATH = "/etc/mon/monshow";
58
59 my %OPSTAT = %Mon::Client::OPSTAT;
60 my $WORD = '[a-zA-Z0-9_-]+';
61 my $OUT_BUF = "";
62 my $e;
63 $= = 1000;
64 $SIG{INT} = \&handle_sig;
65 $SIG{TERM} = \&handle_sig;
66
67 # safe $PATH for taint mode
68 $ENV{PATH} = '/usr/local/bin:/usr/bin:/bin';
69
70 my ($DEP, $GROUP, $SERVICE, $STATUS, $TIME, $NEXT, $ALERTS, $SUMMARY, $DESC);
71
72 # Untaint args, tainting is just for stuff which comes from CGI.
73 for (@ARGV) {
74 /(.*)/s or die;
75 $_ = $1;
76 }
77
78 my %opt;
79 GetOptions (\%opt, "showall", "auth", "help", "full", "disabled",
80 "rcfile=s", "login=s", "server=s", "port=i", "prot=s",
81 "detail=s", "view=s") || usage;
82
83 @ARGV == 0 || usage "No non-switch args expected\n";
84
85 my $CGI;
86 my %QUERY_ARGS;
87 if (defined $ENV{"REQUEST_METHOD"})
88 {
89 unless ($CGI = new CGI)
90 {
91 $CGI = 1;
92 err_die ("Can't create CGI object\n");
93 }
94 }
95
96 if (!$CGI && $opt{"help"})
97 {
98 usage;
99 }
100
101 if ($CGI)
102 {
103 foreach my $e (split (/\?/, $ENV{"QUERY_STRING"}))
104 {
105 next if ($e !~ /=/);
106
107 my ($var, $val) = split (/=/, $e);
108
109 $QUERY_ARGS{$var} = $val;
110 }
111 }
112
113 my $CF = {
114 "host" => "localhost",
115 "full" => 0,
116 "show-disabled" => 0,
117 "bg" => "d5d5d5",
118 "bg-ok" => "a0d0a0",
119 "bg-fail" => "e088b7",
120 "bg-untested" => "e0e0e0",
121 "table-color" => "cccccc",
122 "summary-len" => 20,
123 };
124
125 my $GLOBAL = {
126 "view-name" => undef,
127 };
128
129 #
130 # read config file
131 #
132 my ($e, $what) = read_cf ($CF);
133
134 if ($e ne "")
135 {
136 err_die ("while reading config file, $e");
137 }
138
139 #
140 # cmdline args override config file
141 #
142 if (!$CGI)
143 {
144 $CF->{"all"} = 1 if ($opt{"showall"});
145 $CF->{"full"} = 1 if ($opt{"full"});
146 $CF->{"detail"} = $opt{"detail"} if ($opt{"detail"} ne "");
147 $CF->{"host"} = $opt{"server"} if ($opt{"server"});
148 $CF->{"port"} = $opt{"port"} if ($opt{"port"});
149 $CF->{"prot"} = $opt{"prot"} if ($opt{"prot"});
150 }
151
152 #
153 # retrieve client status
154 #
155 my ($e, $st) = get_client_status ($what);
156
157 if ($e ne "")
158 {
159 err_die ($e);
160 }
161
162 expand_watch ($what, $st);
163
164 my $rows = select_table ($what, $st);
165
166 compose_header ($st->{"state"});
167
168 #
169 # CGI invocation
170 #
171 if ($CGI)
172 {
173 if ($QUERY_ARGS{"disabled"})
174 {
175 compose_disabled ($st->{"disabled"});
176 }
177
178 elsif (!$QUERY_ARGS{"detail"})
179 {
180 compose_table ($rows, $st);
181
182 compose_disabled ($st->{"disabled"}) if ($CF->{"show-disabled"});
183 }
184
185 elsif ($QUERY_ARGS{"detail"})
186 {
187 compose_detail ($QUERY_ARGS{"detail"}, $st);
188 }
189 }
190
191 #
192 # cmdline invocation
193 #
194 else
195 {
196 if ($opt{"disabled"})
197 {
198 compose_disabled ($st->{"disabled"});
199 }
200
201 elsif ($CF->{"detail"} ne "")
202 {
203 compose_detail ($CF->{"detail"}, $st);
204 }
205
206 else
207 {
208 compose_table ($rows, $st);
209
210 compose_disabled ($st->{"disabled"}) if ($CF->{"show-disabled"});
211 }
212 }
213
214 compose_trailer;
215
216 if ($CGI)
217 {
218 print <<EOF;
219 Content-type: text/html
220
221 $OUT_BUF
222 EOF
223 }
224
225 else
226 {
227 print "\n";
228 }
229
230 exit;
231
232 #-----------------------------------------------------------------------------
233
234 format STDOUT_TOP =
235
236 GROUP SERVICE STATUS LAST NEXT ALERTS SUMMARY
237 .
238
239
240 #
241 # usage
242 #
243 sub usage
244 {
245 print STDERR @_, <<EOF;
246
247 usage: monshow [--auth] [--showall] [--full] [--login user] [--disabled]
248 [--server host] [--port num] [--rcfile file]
249 [--detail group,service] [--view name]
250 --showall do not read rcfile and show opstatus of all services
251 --full show disabled, failures, successes, and untested
252 --detail g,s show detail (alert acks, etc.) for group,service
253 --view name display a pre-defined view
254 --auth authenticate to mon server
255 --disabled show disabled
256 --prot ver set protocol version, must match 1.2.3 format
257 --login user use "login" as username while authenticating
258 --server host use "host" as monhost, instead of MONHOST
259 --port num use "num" as port number instead of default
260 --rcfile file use "file" as config file instead of \$HOME/.monshowrc
261
262 EOF
263
264 exit 1;
265 }
266
267
268 #
269 # signal handler
270 #
271 sub handle_sig
272 {
273 system "stty echo" unless ($CGI);
274 exit;
275 }
276
277
278 #
279 # get auth info
280 #
281 # returns a list "error", "login", "password"
282 #
283 sub get_auth
284 {
285 my ($login, $pass);
286
287 if ($CGI)
288 {
289 $login = $CGI->query ("login");
290 $pass = $CGI->query ("password");
291 }
292
293 else
294 {
295 if ($opt{"login"})
296 {
297 $login = $opt{"login"};
298 }
299
300 else
301 {
302 return "could not determine username"
303 if (!defined ($login = getpwuid($EUID)));
304 }
305
306 if (-t STDIN)
307 {
308 system "stty -echo";
309 print "Password: ";
310 chop ($pass = <STDIN>);
311 print "\n";
312 system "stty echo";
313 return "invalid password" if ($pass =~ /^\s*$/);
314 }
315
316 else
317 {
318 my $cmd;
319
320 while (defined ($cmd = <>))
321 {
322 chomp $cmd;
323 if ($cmd =~ /^user=(\S+)$/i)
324 {
325 $login = $1;
326 }
327
328 elsif ($cmd =~ /^pass=(\S+)$/i)
329 {
330 $pass = $1;
331 }
332
333 last if (defined ($login) && defined ($pass));
334 }
335 }
336 }
337
338 return "inadequate authentication information supplied"
339 if ($login eq "" || $pass eq "");
340
341 return ("", $login, $pass);
342 }
343
344 #
345 # config file
346 #
347 sub read_cf
348 {
349 my $CF = shift;
350
351 my ($group, $service);
352 my @RC;
353 my $view = 0;
354
355 my $RC = "/etc/mon/monshowrc";
356
357 if ($CGI)
358 {
359 if ($ENV{"PATH_INFO"} =~ /^\/\S+/)
360 {
361 my $p=$ENV{"PATH_INFO"};
362 $p =~ s/^[.\/]*//;
363 $p =~ s/\/*$//;
364 $p =~ s/\.\.//g;
365 $RC = "$VIEWPATH/$p";
366 $GLOBAL->{"view-name"} = $p;
367 $view = 1;
368 }
369
370 elsif ($QUERY_ARGS{"view"} ne "")
371 {
372 $QUERY_ARGS{"view"} =~ s/^[.\/]*//;
373 $QUERY_ARGS{"view"} =~ s/\.\.//g;
374 $GLOBAL->{"view-name"} = $QUERY_ARGS{"view"};
375 $RC = "$VIEWPATH/$QUERY_ARGS{view}";
376 $view = 1;
377 }
378
379 elsif (-f ".monshowrc")
380 {
381 $RC = ".monshowrc";
382 }
383 }
384
385 else
386 {
387 if ($opt{"rcfile"})
388 {
389 $RC = $opt{"rcfile"};
390 }
391
392 elsif ($opt{"view"} ne "")
393 {
394 $RC = "$VIEWPATH/$opt{view}";
395 $GLOBAL->{"view-name"} = $opt{"view"};
396 $view = 1;
397 }
398
399 elsif (-f "$ENV{HOME}/.monshowrc")
400 {
401 $RC = "$ENV{HOME}/.monshowrc";
402 }
403 }
404
405 if ($opt{"old"})
406 {
407 $CF->{"prot"} = "0.37.0";
408 $CF->{"port"} = 32777;
409 }
410
411 if (-f $RC)
412 {
413 open (IN, $RC) || return "could not read $RC: $!";
414
415 my $html_header = 0;
416 my $link_text = 0;
417 my $link_group = "";
418 my $link_service = "";
419
420 while (<IN>)
421 {
422 next if (/^\s*#/ || /^\s*$/);
423
424 if ($html_header)
425 {
426 if (/^END\s*$/)
427 {
428 $html_header = 0;
429 next;
430 }
431
432 else
433 {
434 $CF->{"html-header"} .= $_;
435 next;
436 }
437 }
438
439 elsif ($link_text)
440 {
441 if (/^END\s*$/)
442 {
443 $link_text = 0;
444 next;
445 }
446
447 else
448 {
449 $CF->{"links"}->{$link_group}->{$link_service}->{"link-text"} .= $_;
450 next;
451 }
452 }
453
454 else
455 {
456 chomp;
457 s/^\s*//;
458 s/\s*$//;
459 }
460
461 if (/^set \s+ (\S+) \s* (\S+)?/ix)
462 {
463 my $cmd = $1;
464 my $arg = $2;
465 if ($cmd eq "show-disabled") { }
466 elsif ($cmd eq "host") { }
467 elsif ($cmd eq "prot") { }
468 elsif ($cmd eq "port") { }
469 elsif ($cmd eq "full") { }
470 elsif ($cmd eq "bg") { }
471 elsif ($cmd eq "bg-ok") { }
472 elsif ($cmd eq "bg-fail") { }
473 elsif ($cmd eq "bg-untested") { }
474 elsif ($cmd eq "table-color") { }
475 elsif ($cmd eq "html-header") { $html_header = 1; next; }
476 elsif ($cmd eq "refresh") { }
477 elsif ($cmd eq "summary-len") { }
478 else
479 {
480 print STDERR "unknown set, line $.\n";
481 next;
482 }
483
484 if ($arg ne "")
485 {
486 $CF->{$cmd} = $arg;
487 }
488
489 else
490 {
491 $CF->{$cmd} = 1;
492 }
493 }
494
495 elsif (/^watch \s+ (\S+)/x)
496 {
497 push (@RC, [$1]);
498 }
499
500 elsif (/^service \s+ (\S+) \s+ (\S+)/x)
501 {
502 push (@RC, [$1, $2]);
503 }
504
505 elsif (/^link \s+ (\S+) \s+ (\S+) \s+ (.*)\s*/ix)
506 {
507 $CF->{"links"}->{$1}->{$2}->{"link"} = $3;
508 }
509
510 elsif (/^link-text \s+ (\S+) \s+ (\S+)/ix)
511 {
512 $link_text = 1;
513 $link_group = $1;
514 $link_service = $2;
515 next;
516 }
517
518 else
519 {
520 my $lnum = $.;
521 close (IN);
522 err_die ("error in config file, line $.");
523 }
524 }
525 close (IN);
526 }
527
528 elsif (! -f $RC && $view)
529 {
530 err_die ("no view found");
531 }
532
533 return ("", \@RC);
534 }
535
536
537 sub secs_to_hms
538 {
539 my ($s) = @_;
540 my ($dd, $hh, $mm, $ss);
541
542 $dd = int ($s / 86400);
543 $s -= $dd * 86400;
544
545 $hh = int ($s / 3600);
546 $s -= $hh * 3600;
547
548 $mm = int ($s / 60);
549 $s -= $mm * 60;
550
551 $ss = $s;
552
553 if ($dd == 0)
554 {
555 sprintf("%02d:%02d", $hh, $mm);
556 }
557
558 else
559 {
560 sprintf("%d days, %02d:%02d", $dd, $hh, $mm);
561 }
562 }
563
564
565 #
566 # exit displaying error in appropriate output format
567 #
568 sub err_die
569 {
570 my $msg = shift;
571
572 if ($CGI)
573 {
574 print <<EOF;
575 Content-type: text/html
576
577 <html>
578 <head>
579 <title> Error </title>
580 </head>
581 <body>
582 <h2> Error </h2>
583 <pre>
584 $msg
585 </pre>
586 </body>
587 </html>
588 EOF
589 }
590
591 else
592 {
593 print <<EOF;
594 Error: $msg
595
596 EOF
597 }
598
599 exit 1;
600 }
601
602
603 #
604 # everything is cool
605 #
606 sub display_allok
607 {
608 if ($CGI)
609 {
610 $OUT_BUF .= <<EOF;
611 <h2> All systems OK </h2>
612 <p>
613
614 EOF
615 }
616
617 else
618 {
619 print "\nAll systems OK\n";
620 }
621 }
622
623
624 #
625 # client status
626 #
627 # return ("", $state, \%opstatus, \%disabled, \%deps, \%groups, \%descriptions);
628 #
629 sub get_client_status {
630 my $what = shift;
631
632 my $cl;
633
634 if (!defined ($cl = Mon::Client->new))
635 {
636 return "could not create client object: $@";
637 }
638
639 my ($username, $pass);
640
641 if ($opt{"auth"} && !$CGI)
642 {
643 my $e;
644 ($e, $username, $pass) = get_auth;
645 if ($e ne "")
646 {
647 return "$e";
648 }
649 $cl->username ($username);
650 $cl->password ($pass);
651 }
652
653 $cl->host ($CF->{"host"}) if (defined $CF->{"host"});
654 $cl->port ($CF->{"port"}) if (defined $CF->{"port"});
655 $cl->port ($CF->{"prot"}) if (defined $CF->{"prot"});
656
657 $cl->connect;
658
659 if ($cl->error) {
660 return "Could not connect to server: " . $cl->error;
661 }
662
663 #
664 # authenticate self to the server if necessary
665 #
666 if ($opt{"auth"} && !defined ($cl->login)) {
667 my $e = $cl->error;
668 $cl->disconnect;
669 return "Could authenticate: $e";
670 }
671
672 #
673 # get disabled things
674 #
675 my %disabled = $cl->list_disabled;
676 if ($cl->error) {
677 my $e = $cl->error;
678 $cl->disconnect;
679 return "could not get disabled: $e";
680 }
681
682 #
683 # get state
684 #
685 my ($running, $t) = $cl->list_state;
686 if ($cl->error) {
687 my $e = $cl->error;
688 $cl->disconnect;
689 return "could not get state: $e";
690 }
691
692 my $state;
693 if ($running) {
694 $state = $t;
695 }
696
697 else
698 {
699 $state = "scheduler stopped since " . localtime ($t);
700 }
701
702 #
703 # group/service list
704 #
705 my @watch = $cl->list_watch;
706
707 if ($cl->error) {
708 my $e = $cl->error;
709 $cl->disconnect;
710 return "could not get opstatus: $e";
711 }
712
713 #
714 # get opstatus
715 #
716 my %opstatus;
717 if (@{$what} == 0)
718 {
719 %opstatus = $cl->list_opstatus;
720 if ($cl->error) {
721 my $e = $cl->error;
722 $cl->disconnect;
723 return "could not get opstatus: $e";
724 }
725 }
726
727 else
728 {
729 my @list;
730 foreach my $r (@{$what})
731 {
732 if (@{$r} == 2)
733 {
734 push @list, $r;
735 }
736
737 else
738 {
739 foreach my $w (@watch)
740 {
741 next if ($r->[0] ne $w->[0]);
742 push @list, $w;
743 }
744 }
745 }
746
747 %opstatus = $cl->list_opstatus (@list);
748 if ($cl->error) {
749 my $e = $cl->error;
750 $cl->disconnect;
751 return "could not get opstatus: $e";
752 }
753 }
754
755 #
756 # dependencies
757 #
758 my %deps;
759 if ($opt{"deps"}) {
760 %deps = $cl->list_deps;
761 if ($cl->error) {
762 my $e = $cl->error;
763 $cl->disconnect;
764 return "could not list deps: $e";
765 }
766 }
767
768 #
769 # descriptions
770 #
771 my %desc;
772 %desc = $cl->list_descriptions;
773 if ($cl->error) {
774 my $e = $cl->error;
775 $cl->disconnect;
776 return "could not list descriptions: $e";
777 }
778
779 #
780 # groups
781 #
782 my %groups;
783
784 if ($QUERY_ARGS{"detail"} || $CF->{"detail"} ne "")
785 {
786 foreach my $g (keys %opstatus)
787 {
788 my @g = $cl->list_group ($g);
789 if ($cl->error)
790 {
791 my $e = $cl->error;
792 $cl->disconnect;
793 return "could not list group: $e";
794 }
795
796 grep {s/\*//} @g;
797 $groups{$g} = [@g];
798 }
799 }
800
801 #
802 # log out
803 #
804 if (!defined $cl->disconnect) {
805 return "error while disconnecting: " . $cl->error;
806 }
807
808
809 return ("", {
810 "state" => $state,
811 "opstatus" => \%opstatus,
812 "disabled" => \%disabled,
813 "deps" => \%deps,
814 "groups" => \%groups,
815 "desc" => \%desc,
816 "watch" => \@watch,
817 });
818 }
819
820
821 sub compose_header {
822 my $state = shift;
823
824 my $t = localtime;
825
826 #
827 # HTML stuff
828 #
829 if ($CGI)
830 {
831 $OUT_BUF = <<EOF;
832 <html>
833 <head>
834 <title> Operational Status </title>
835 EOF
836
837 if ($CF->{"refresh"})
838 {
839 $OUT_BUF .= <<EOF;
840 <META HTTP-EQUIV="Pragma" CONTENT="no-cache">
841 <META HTTP-EQUIV="Refresh" CONTENT=$CF->{refresh}>
842 EOF
843 }
844
845 $OUT_BUF .= <<EOF;
846 </head>
847 <body bgcolor="#$CF->{'bg'}">
848 EOF
849
850 if ($CF->{"html-header"} ne "")
851 {
852 $OUT_BUF .= $CF->{"html-header"};
853 }
854
855 $OUT_BUF .= <<EOF;
856 <h1><FONT FACE="sans-serif">Operational Status</font></h1>
857
858 <table width="100%">
859 <tr>
860 <td>
861 <table>
862 <tr>
863 <td align=right><b>Server:</b></td>
864 <td> $CF->{host} </td>
865 </tr>
866 <tr>
867 <td align=right><b>Time:</b></td>
868 <td> $t </td>
869 </tr>
870 <tr>
871 <td align=right><b>State:</b></td>
872 <td> $state </td>
873 </tr>
874 EOF
875
876 if ($GLOBAL->{"view-name"} ne "")
877 {
878 $OUT_BUF .= <<EOF;
879 <tr>
880 <td align=right><b>View:</b></td>
881 <td><b>$GLOBAL->{"view-name"}</b></td>
882 </tr>
883 EOF
884 }
885
886 $OUT_BUF .= <<EOF;
887 </table>
888 </td>
889
890 <td>
891 <table>
892 <tr>
893 <td><FONT FACE="sans-serif">Color legend</FONT></td>
894 </tr>
895 <tr>
896 <td bgcolor="#$CF->{'bg-ok'}"> all is OK </td>
897 </tr>
898 <tr>
899 <td bgcolor="#$CF->{'bg-fail'}"> failure </td>
900 </tr>
901 <tr>
902 <td bgcolor="#$CF->{'bg-untested'}"> untested </td>
903 </tr>
904 </table>
905 </td>
906 </tr>
907 </table>
908 <p>
909 <hr>
910 EOF
911 }
912
913 else
914 {
915 print <<EOF;
916
917 server: $CF->{host}
918 time: $t
919 state: $state
920 EOF
921 }
922 }
923
924
925 sub select_table {
926 my ($what, $st) = @_;
927
928 my @rows;
929
930 #
931 # display everything real nice
932 #
933 if ($CF->{"all"} || @{$what} == 0)
934 {
935 foreach my $group (keys %{$st->{"opstatus"}})
936 {
937 foreach my $service (keys %{$st->{"opstatus"}->{$group}})
938 {
939 push (@rows, [$group, $service]);
940 }
941 }
942 }
943
944 else
945 {
946 @rows = @{$what};
947 }
948
949 my (%DEP, %DEPROOT);
950
951 foreach my $l (@rows)
952 {
953 my ($group, $service) = @{$l};
954
955 my $sref = \%{$st->{"opstatus"}->{$group}->{$service}};
956
957 next if (!defined $sref->{"opstatus"});
958
959 #
960 # disabled things
961 #
962 # fuckin' Perl, man. Just be referencing
963 # $st->{"disabled"}->{"watches"}->{$group}, perl automagically
964 # defines that hash element for you. Great.
965 #
966 if (defined ($st->{"disabled"}->{"watches"}) &&
967 defined ($st->{"disabled"}->{"watches"}->{$group}))
968 {
969 next;
970 }
971
972 elsif (defined ($st->{"disabled"}->{"services"}) &&
973 defined ($st->{"disabled"}->{"services"}->{$group}) &&
974 defined ($st->{"disabled"}->{"services"}->{$service}))
975 {
976 next;
977 }
978
979 #
980 # potential root dependencies
981 #
982 elsif ($sref->{"depend"} eq "")
983 {
984 push (@{$DEPROOT{$sref->{"opstatus"}}}, ["R", $group, $service]);
985 }
986
987 #
988 # things which have dependencies
989 #
990 else
991 {
992 push (@{$DEP{$sref->{"opstatus"}}}, ["D", $group, $service]);
993 }
994 }
995
996 if ($CF->{"full"})
997 {
998 [
999 @{$DEPROOT{$OPSTAT{"fail"}}},
1000 @{$DEPROOT{$OPSTAT{"linkdown"}}},
1001 @{$DEPROOT{$OPSTAT{"timeout"}}},
1002 @{$DEPROOT{$OPSTAT{"coldstart"}}},
1003 @{$DEPROOT{$OPSTAT{"warmstart"}}},
1004 @{$DEPROOT{$OPSTAT{"untested"}}},
1005 @{$DEPROOT{$OPSTAT{"unknown"}}},
1006
1007 @{$DEP{$OPSTAT{"fail"}}},
1008 @{$DEP{$OPSTAT{"linkdown"}}},
1009 @{$DEP{$OPSTAT{"timeout"}}},
1010 @{$DEP{$OPSTAT{"coldstart"}}},
1011 @{$DEP{$OPSTAT{"warmstart"}}},
1012
1013 @{$DEPROOT{$OPSTAT{"ok"}}},
1014 @{$DEP{$OPSTAT{"ok"}}},
1015 @{$DEP{$OPSTAT{"untested"}}},
1016 @{$DEP{$OPSTAT{"unknown"}}},
1017 ];
1018 }
1019
1020 else
1021 {
1022 [
1023 @{$DEPROOT{$OPSTAT{"fail"}}},
1024 @{$DEPROOT{$OPSTAT{"linkdown"}}},
1025 @{$DEPROOT{$OPSTAT{"timeout"}}},
1026 @{$DEPROOT{$OPSTAT{"coldstart"}}},
1027 @{$DEPROOT{$OPSTAT{"warmstart"}}},
1028
1029 @{$DEP{$OPSTAT{"fail"}}},
1030 @{$DEP{$OPSTAT{"linkdown"}}},
1031 @{$DEP{$OPSTAT{"timeout"}}},
1032 @{$DEP{$OPSTAT{"coldstart"}}},
1033 @{$DEP{$OPSTAT{"warmstart"}}},
1034 ];
1035 }
1036 }
1037
1038
1039 #
1040 # build the table
1041 #
1042 sub compose_table {
1043 my ($rows, $st) = @_;
1044
1045 if (@{$rows} == 0)
1046 {
1047 display_allok;
1048 return;
1049 }
1050
1051 #
1052 # display the failure table
1053 #
1054 if ($CGI)
1055 {
1056 $OUT_BUF .= <<EOF;
1057
1058 <table cellpadding=2 cellspacing=1 bgcolor="#$CF->{'table-color'}" width="100%">
1059 <tr>
1060 <th><FONT FACE="sans-serif">Dep</FONT></th>
1061 <th><FONT FACE="sans-serif">Group</FONT></th>
1062 <th><FONT FACE="sans-serif">Service</FONT></th>
1063 <th><FONT FACE="sans-serif">Desc.</FONT></th>
1064 <th><FONT FACE="sans-serif">Last check</FONT></th>
1065 <th><FONT FACE="sans-serif">Next check</FONT></th>
1066 <th><FONT FACE="sans-serif">Alerts</FONT></th>
1067 <th><FONT FACE="sans-serif">Status</FONT></th>
1068 <th><FONT FACE="sans-serif">Summary</FONT></th>
1069 </tr>
1070
1071 EOF
1072 }
1073
1074 foreach my $l (@{$rows})
1075 {
1076 my ($depstate, $group, $service) = @{$l};
1077
1078 my $sref = \%{$st->{"opstatus"}->{$group}->{$service}};
1079
1080 $STATUS = "unknown";
1081 $TIME = "";
1082 $DEP = $depstate;
1083 my $last = "";
1084 my $bgcolor = opstatus_color ($sref->{"opstatus"});
1085
1086 if ($sref->{"opstatus"} == $OPSTAT{"untested"})
1087 {
1088 $STATUS = "untested";
1089 $TIME = "untested";
1090 }
1091
1092 elsif ($sref->{"opstatus"} == $OPSTAT{"ok"})
1093 {
1094 $STATUS = "-";
1095 }
1096
1097 elsif ($sref->{"opstatus"} == $OPSTAT{"fail"})
1098 {
1099 if ($sref->{"ack"})
1100 {
1101 if ($CGI) {
1102 $STATUS = "<a href=\"$ENV{SCRIPT_NAME}?detail=$group,$service\">" .
1103 "<b>ACK FAIL</b></a>";
1104 } else {
1105 $STATUS = "ACK FAIL";
1106 }
1107 }
1108
1109 else
1110 {
1111 $STATUS = "FAIL";
1112 }
1113 }
1114
1115 if ($depstate eq "")
1116 {
1117 $DEP = "-";
1118 }
1119
1120 $GROUP = $group;
1121 $SERVICE = $service;
1122 $DESC = $st->{"desc"}->{$group}->{$service};
1123
1124 $DESC = pre_pad_if_empty ($DESC) if ($CGI);
1125
1126
1127 if ($TIME eq "")
1128 {
1129 $TIME = tdiff_string (time - $sref->{"last_check"});
1130 }
1131
1132 if ($sref->{"timer"} < 60)
1133 {
1134 $NEXT = "$sref->{timer}s";
1135 }
1136
1137 else
1138 {
1139 $NEXT = secs_to_hms ($sref->{"timer"});
1140 }
1141
1142 if (length ($sref->{"last_summary"}) > $CF->{"summary-len"})
1143 {
1144 $SUMMARY = substr ($sref->{"last_summary"}, 0, $CF->{"summary-len"}) . "...";
1145 }
1146
1147 else
1148 {
1149 $SUMMARY = $sref->{"last_summary"};
1150 }
1151
1152
1153 $ALERTS = $sref->{"alerts_sent"} || "none";
1154
1155 my $fmt;
1156 if (!$CGI)
1157 {
1158 $fmt = <<EOF;
1159 format STDOUT =
1160 @ @<<<<<<<<<<<<<< @<<<<<<<<<<< @<<<<<<<<< @<<<<<<< @<<<<<<<<< @<<< @
1161 EOF
1162 chomp $fmt;
1163 $fmt .= "<" x length($SUMMARY) . "\n";
1164 $fmt .= <<'EOF';
1165 $DEP, $GROUP, $SERVICE, $STATUS, $TIME, $NEXT, $ALERTS, $SUMMARY
1166 .
1167 EOF
1168 eval $fmt;
1169 write;
1170 }
1171
1172 else
1173 {
1174 if ($SUMMARY =~ /^[\s\n]*$/)
1175 {
1176 $SUMMARY = "<pre> </pre>";
1177 }
1178
1179 else
1180 {
1181 $SUMMARY = "<small>$SUMMARY</small>";
1182 }
1183
1184 if ($bgcolor ne "")
1185 {
1186 $bgcolor = "bgcolor=\"#$bgcolor\"";
1187 }
1188 $OUT_BUF .= <<EOF;
1189
1190 <tr $bgcolor>
1191 <td> $DEP </td>
1192 <td> $GROUP </td>
1193 <td> <a href="$ENV{SCRIPT_NAME}?detail=$group,$service">$SERVICE</a> </td>
1194 <td> <small>$DESC</small> </td>
1195 <td> $TIME </td>
1196 <td> $NEXT </td>
1197 <td> $ALERTS </td>
1198 <td> $STATUS </td>
1199 <td> $SUMMARY </td>
1200 </tr>
1201 EOF
1202
1203 }
1204 }
1205
1206 if ($CGI)
1207 {
1208 $OUT_BUF .= <<EOF;
1209 </table>
1210
1211 EOF
1212 }
1213 }
1214
1215
1216 sub compose_disabled {
1217 my $disabled = shift;
1218
1219 if (!keys %{$disabled->{"watches"}} &&
1220 !keys %{$disabled->{"services"}} &&
1221 !keys %{$disabled->{"hosts"}})
1222 {
1223 if ($CGI)
1224 {
1225 $OUT_BUF .= <<EOF;
1226 <br>
1227 Nothing is disabled.
1228 <p>
1229 EOF
1230 }
1231
1232 else
1233 {
1234 print "\nNothing is disabled.\n";
1235 }
1236
1237 return;
1238 }
1239
1240 if (keys %{$disabled->{"watches"}})
1241 {
1242 if ($CGI)
1243 {
1244 $OUT_BUF .= <<EOF;
1245
1246 <h2> Disabled Watches </h2>
1247
1248 EOF
1249 }
1250
1251 else
1252 {
1253 print "\nDISABLED WATCHES:\n";
1254 }
1255
1256 foreach my $watch (keys %{$disabled->{"watches"}})
1257 {
1258 if ($CGI)
1259 {
1260 $OUT_BUF .= "$watch <br>\n";
1261 }
1262
1263 else
1264 {
1265 print "$watch\n";
1266 }
1267 }
1268 }
1269
1270 my @disabled_services;
1271 foreach my $watch (keys %{$disabled->{"services"}})
1272 {
1273 foreach my $service (keys %{$disabled->{"services"}{$watch}})
1274 {
1275 push (@disabled_services, "$watch $service");;
1276 }
1277 }
1278
1279 if (@disabled_services)
1280 {
1281 if ($CGI)
1282 {
1283 $OUT_BUF .= <<EOF;
1284
1285 <h2> Disabled Services </h2>
1286
1287 EOF
1288 }
1289
1290 else
1291 {
1292 print "\nDISABLED SERVICES\n";
1293 }
1294 for (@disabled_services)
1295 {
1296 if ($CGI)
1297 {
1298 $OUT_BUF .= "$_ <br>\n";
1299 }
1300
1301 else
1302 {
1303 print "$_\n";
1304 }
1305 }
1306 }
1307
1308 if (keys %{$disabled->{"hosts"}})
1309 {
1310 if ($CGI)
1311 {
1312 $OUT_BUF .= <<EOF;
1313
1314 <h2> Disabled Hosts </h2>
1315
1316 EOF
1317 }
1318
1319 else
1320 {
1321 print "\nDISABLED HOSTS:\n";
1322 }
1323 foreach my $group (keys %{$disabled->{"hosts"}})
1324 {
1325 my @HOSTS = ();
1326 foreach my $host (keys %{$disabled->{"hosts"}{$group}})
1327 {
1328 push (@HOSTS, $host);
1329 }
1330 if ($CGI)
1331 {
1332 $OUT_BUF .= sprintf ("%-15s %s <br>\n", $group, "@HOSTS");
1333 }
1334
1335 else
1336 {
1337 printf ("%-15s %s\n", $group, "@HOSTS");
1338 }
1339 }
1340 }
1341 }
1342
1343
1344 sub compose_trailer {
1345 if ($CGI)
1346 {
1347 $OUT_BUF .= <<EOF;
1348 </body>
1349 </html>
1350 EOF
1351 }
1352 }
1353
1354
1355 sub compose_detail {
1356 my ($args, $st) = @_;
1357
1358 my ($group, $service) = split (/,/, $args, 2);
1359
1360 if (!defined ($st->{"opstatus"}->{$group}->{$service}))
1361 {
1362 err_die ("$group/$service not a valid service");
1363 }
1364
1365 my $sref = \%{$st->{"opstatus"}->{$group}->{$service}};
1366
1367 my $d;
1368
1369 my $bgcolor = opstatus_color ($sref->{"opstatus"});
1370
1371 $bgcolor = "bgcolor=\"#$bgcolor\"" if ($bgcolor ne "");
1372
1373 foreach my $k (keys %OPSTAT)
1374 {
1375 if ($OPSTAT{$k} == $sref->{"opstatus"})
1376 {
1377 $sref->{"opstatus"} = "$k ($sref->{opstatus})";
1378 last;
1379 }
1380 }
1381
1382 foreach my $k (qw (opstatus exitval last_check timer ack ackcomment))
1383 {
1384 if ($CGI && $sref->{$k} =~ /^\s*$/)
1385 {
1386 $d->{$k} = "<pre> </pre>";
1387 }
1388
1389 else
1390 {
1391 $d->{$k} = $sref->{$k};
1392 }
1393 }
1394
1395 my $t = time;
1396
1397 $d->{"last_check"} = tdiff_string ($t - $d->{"last_check"}) . " ago";
1398 $d->{"timer"} = "in " . tdiff_string ($d->{"timer"});
1399
1400 foreach my $k (qw (last_success last_failure first_failure last_alert))
1401 {
1402 if ($sref->{$k})
1403 {
1404 $d->{$k} = localtime ($sref->{$k});
1405 }
1406 }
1407
1408 if ($sref->{"first_failure"})
1409 {
1410 $d->{"failure_duration"} = secs_to_hms ($sref->{"failure_duration"});
1411 }
1412
1413
1414 #
1415 # HTML output
1416 #
1417 if ($CGI)
1418 {
1419 my $sum = pre_pad_if_empty ($sref->{"last_summary"});
1420 my $descr = pre_pad_if_empty ($st->{"desc"}->{$group}->{$service});
1421 my $hosts = pre_pad_if_empty ("@{$st->{groups}->{$group}}");
1422
1423 $OUT_BUF .= <<EOF;
1424
1425 <h2><FONT FACE="sans-serif">Detail for $group/$service</font></h2>
1426
1427 <table width="100%">
1428 <tr $bgcolor>
1429 <td align=right width="15%"> <b> Description: </b> <td> $descr
1430 <tr $bgcolor>
1431 <td align=right width="15%"> <b> Summary: </b> <td> $sum
1432 <tr $bgcolor>
1433 <td align=right width="15%"> <b> Hosts: </b> <td> $hosts
1434 <tr $bgcolor>
1435 <td valign=top align=right width="15%"> <b> Detail: </b>
1436 <td>
1437 <pre>
1438 $sref->{last_detail}
1439 </pre>
1440 </table>
1441 EOF
1442
1443 if ($d->{"ack"}) {
1444 my $comment = pre_pad_if_empty ($d->{"ackcomment"});
1445
1446 $OUT_BUF .= <<EOF;
1447 <table width="100%">
1448 <tr>
1449 <td align=right width="15%"> <h2>Acknowledgment of failure</h2> </td>
1450 <tr>
1451 <td align=right width="15%"> $comment
1452 </table>
1453
1454 EOF
1455 }
1456
1457 $OUT_BUF .= <<EOF;
1458 <table cellpadding=2 cellspacing=1 bgcolor="#CCCCCC" width="100%">
1459 EOF
1460
1461 #
1462 # 0 = nothing special
1463 # 1 = do not display if zero
1464 # 2 = do not display if eq ""
1465 #
1466 foreach my $k (
1467 ["opstatus", "Operational Status", 0],
1468 ["exitval", "Exit Value", 0],
1469 ["depend", "Dependency", 2],
1470 ["monitor", "Monitor Program", 2],
1471 ["last_check", "Last Check", 2],
1472 ["timer", "Next Check", 2],
1473 ["last_success", "Last Success", 2],
1474 ["last_failure", "Last Failure", 2],
1475 ["first_failure", "First Failure", 2],
1476 ["failure_duration", "Failure Duration", 2],
1477 ["interval", "Schedule Interval", 0],
1478 ["exclude_period", "Exclude Period", 2],
1479 ["exclude_hosts", "Exclude Hosts", 2],
1480 ["randskew", "Random Skew", 1],
1481 ["alerts_sent", "Alerts Sent", 1],
1482 ["last_alert", "Last Alert", 2])
1483 {
1484 my $v = undef;
1485
1486 if ($d->{$k->[0]} ne "") {
1487 $v = \$d->{$k->[0]};
1488
1489 } elsif ($sref->{$k->[0]} ne "") {
1490 $v = \$sref->{$k->[0]};
1491 }
1492
1493 next if ($k->[2] == 1 && $$v == 0);
1494 next if ($k->[2] == 2 && $$v eq "");
1495
1496 $OUT_BUF .= <<EOF;
1497 <tr>
1498 <td align=right width="15%"><b>$k->[1]:</b></td>
1499 <td> $$v </td>
1500 EOF
1501 }
1502
1503 $OUT_BUF .= <<EOF;
1504 </table>
1505
1506 EOF
1507
1508 #
1509 # custom links
1510 #
1511 if (defined ($CF->{"links"}->{$group}->{$service}))
1512 {
1513 if (defined ($CF->{"links"}->{$group}->{$service}->{"link-text"}))
1514 {
1515 $OUT_BUF .= <<EOF;
1516 <p>
1517 <h2><a href=\"$CF->{links}->{$group}->{$service}->{link}\">More Information</a></h2>
1518 $CF->{links}->{$group}->{$service}->{'link-text'}
1519
1520 EOF
1521 }
1522
1523 else
1524 {
1525 $OUT_BUF .= <<EOF;
1526 <p>
1527 <a href="$CF->{links}->{$group}->{$service}->{link}">$CF->{links}->{$group}->{$service}->{link}</a>
1528
1529 EOF
1530 }
1531 }
1532
1533 $OUT_BUF .= <<EOF;
1534 <p>
1535 <a href="$ENV{SCRIPT_NAME}">Back to summary table</a>
1536 <p>
1537
1538 EOF
1539 }
1540
1541 #
1542 # text output
1543 #
1544 else
1545 {
1546 my $n;
1547 $Text::Wrap::columns = 70;
1548 $n->{"desc"} = wrap (" ", " ", $st->{"desc"}->{$group}->{$service});
1549 $n->{"last_summary"} = wrap (" ", " ", $sref->{"last_summary"});
1550 $n->{"hosts"} = wrap (" ", " ", join (" ", @{$st->{groups}->{$group}}));
1551
1552 print <<EOF;
1553
1554 Detail for group $group service $service
1555
1556 description
1557 -----------
1558 $n->{desc}
1559 summary
1560 -------
1561 $n->{last_summary}
1562 hosts
1563 -----
1564 $n->{hosts}
1565
1566 -----DETAIL-----
1567 $sref->{last_detail}
1568 -----DETAIL-----
1569
1570 EOF
1571 if ($d->{"ack"})
1572 {
1573 print <<EOF;
1574 alert ack: $d->{ackcomment}
1575
1576 EOF
1577 }
1578
1579 print <<EOF;
1580 opstatus: $d->{opstatus}
1581 exitval: $d->{exitval}
1582 depend: $d->{depend}
1583 monitor: $d->{monitor}
1584 last check: $d->{last_check}
1585 next_check: $d->{timer}
1586
1587 EOF
1588 }
1589 }
1590
1591
1592 sub opstatus_color {
1593 my $o = shift;
1594
1595 my %color_hash = (
1596 $OPSTAT{"untested"} => $CF->{"bg-untested"},
1597 $OPSTAT{"ok"} => $CF->{"bg-ok"},
1598 $OPSTAT{"fail"} => $CF->{"bg-fail"},
1599 );
1600
1601 $color_hash{$o} || "";
1602 }
1603
1604
1605 sub tdiff_string {
1606 my $time = shift;
1607
1608 my $s;
1609
1610 if ($time <= 90)
1611 {
1612 $s = "${time}s";
1613 }
1614
1615 else
1616 {
1617 $s = secs_to_hms ($time);
1618 }
1619 }
1620
1621
1622 #
1623 # for each watch entry which specifies only "group",
1624 # expand it into "group service"
1625 #
1626 sub expand_watch {
1627 my $what = shift;
1628 my $st = shift;
1629
1630 for (my $i=0; $i<@{$what}; $i++)
1631 {
1632 if (@{$what->[$i]} == 1)
1633 {
1634 my @list;
1635 foreach my $l (@{$st->{"watch"}})
1636 {
1637 if ($l->[0] eq $what->[$i]->[0])
1638 {
1639 push @list, $l;
1640 }
1641 }
1642 splice (@{$what}, $i, 1, @list);
1643 }
1644 }
1645 }
1646
1647
1648 sub pre_pad_if_empty
1649 {
1650 my $l = shift;
1651
1652 return "<pre> </pre>" if ($l =~ /^\s*$/);
1653 $l;
1654 }

  ViewVC Help
Powered by ViewVC 1.1.26