54f164ec27a83a4d8da0618ca8b69ba16d3f8cab
[clearscm.git] / clearadm / lib / ClearadmWeb.pm
1 =pod
2
3 =head1 NAME $RCSfile: ClearadmWeb.pm,v $
4
5 Common routines for the web portion of Clearadm
6
7 =head1 VERSION
8
9 =over
10
11 =item Author
12
13 Andrew DeFaria <Andrew@ClearSCM.com>
14
15 =item Revision
16
17 $Revision: 1.46 $
18
19 =item Created
20
21 Sat Dec 18 08:43:27 EST 2010
22
23 =item Modified
24
25 $Date: 2011/12/26 19:00:58 $
26
27 =back
28
29 =head1 SYNOPSIS
30
31 This module holds common web routines for the web portion of Clearadm.
32
33 =head1 DESCRIPTION
34
35 To be filled out.
36
37 =head1 ROUTINES
38
39 The following routines are exported:
40
41 =cut
42
43 package ClearadmWeb;
44
45 use warnings;
46 use strict;
47
48 use base 'Exporter';
49
50 use CGI qw (
51   :standard
52    start_a
53    end_a
54    start_div
55    end_div
56    start_li
57    end_li
58    start_table
59    end_table
60    start_td
61    end_td
62    start_Tr
63    end_Tr
64    start_ul
65    end_ul
66 );
67
68 use Carp;
69 use File::Basename;
70
71 use FindBin;
72
73 use lib "$FindBin::Bin/../../lib";
74
75 use Clearadm;
76 use Clearcase::Vobs;
77 use Clearcase::Views;
78 use DateUtils;
79 use Display;
80 use Utils;
81
82 my $clearadm = Clearadm->new;
83
84 our $APPNAME= 'Clearadm';
85 our $VERSION  = '$Revision: 1.46 $';
86    ($VERSION) = ($VERSION =~ /\$Revision: (.*) /);
87
88 our @EXPORT = qw (
89   autoScale
90   displayError
91   displayAlert
92   displayAlertlog
93   displayFilesystem
94   displayNotification
95   displayRunlog
96   displaySchedule
97   displaySystem
98   displayTask
99   dbug
100   dumpVars
101   editAlert
102   editFilesystem
103   editNotification
104   editSchedule
105   editSystem
106   editTask
107   footing
108   graphError
109   heading
110   makeAlertDropdown
111   makeFilesystemDropdown
112   makeIntervalDropdown
113   makeNotificationDropdown
114   makeStoragePoolDropdown
115   makeSystemDropdown
116   makeTagsDropdown
117   makeTimeDropdown
118   makeTaskDropdown
119   setField
120   setFields
121 );
122
123 our @PREDEFINED_ALERTS = (
124   'Email admin',
125 );
126
127 our @PREDEFINED_NOTIFICATIONS = (
128   'Clearcase Storage',
129   'Heartbeat',
130   'Loadavg',
131   'Filesystem',
132   'Scrub',
133   'System checkin',
134   'Update systems',
135 );
136
137 our @PREDEFINED_TASKS = (
138   'Clearcase Storage',
139   'Filesystem',
140   'Loadavg',
141   'Scrub',
142   'System checkin',
143   'Update systems',
144 );
145
146 our @PREDEFINED_SCHEDULES = (
147   'Clearcase Storage',
148   'Filesystem',
149   'Loadavg',
150   'Scrub',
151   'Update systems',
152 );
153
154 our @PREDEFINED_NOTMORETHAN = (
155   'Once an hour',
156   'Once a day',
157   'Once a week',
158   'Once a month',
159 );
160
161 our @PREDEFINED_MULTIPLIERS = (
162   'Seconds',
163   'Minutes',
164   'Hours',
165   'Days',
166 );
167
168 sub dbug ($) {
169   my ($msg) = @_;
170
171   display font ({-class => 'error'}, '<br>DEBUG: '). $msg;
172
173   return;
174 } # dbug
175
176 sub displayError ($) {
177   my ($msg) = @_;
178
179   display font ({-class => 'error'}, 'Error: ') . $msg;
180
181   return
182 } # displayError;
183
184 sub setField ($;$) {
185   my ($field, $label) = @_;
186
187   $label ||= 'Unknown';
188
189   my $undef = font {-class => 'unknown'}, $label;
190
191   return defined $field ? $field : $undef;
192 } # setField
193
194 sub setFields ($%) {
195   my ($label, %rec) = @_;
196
197   $rec{$_} = setField ($rec{$_}, $label)
198     for keys %rec;
199
200   return %rec;
201 } # setFields;
202
203 sub dumpVars (%) {
204   my (%vars) = @_;
205
206   for (keys %vars) {
207     dbug "$_: $vars{$_}";
208   } # for
209
210   return;
211 } # dumpVars
212
213 sub graphError ($) {
214   my ($msg) = @_;
215
216   use GD;
217
218   # Make the image fit the message. It seems that characters are ~ 7px wide.
219   my $imageLength = length ($msg) * 7;
220
221   my $errorImage = GD::Image->new ($imageLength, 20);
222
223   # Allocate some colors
224   my $white = $errorImage->colorAllocate (255, 255, 255);
225   my $red   = $errorImage->colorAllocate (255, 0, 0);
226
227   # Allow the text to shine through
228   $errorImage->transparent($white);
229   $errorImage->interlaced('true');
230
231   # Now put out the message
232   $errorImage->string (gdMediumBoldFont, 0, 0, $msg, $red);
233
234   # And return it
235   print "Content-type: image/png\n\n";
236   print $errorImage->png;
237
238   # Since we've "returned" the error in the form of an image, there's nothing
239   # left for us to do so we can exit
240   exit;
241 } # graphError
242
243 sub autoScale ($) {
244   my ($amount) = @_;
245
246   my $kbyte = 1024;
247   my $meg   = (1024 * $kbyte);
248   my $gig   = (1024 * $meg);
249
250   my $size = $amount > $gig
251            ? sprintf ('%.2f Gig',   $amount / $gig)
252            : $amount > $meg
253            ? sprintf ('%.2f Meg',   $amount / $meg)
254            : sprintf ('%.2f Kbyte', $amount / $kbyte);
255
256   return $size;
257 } # autoScale
258
259 sub _makeAlertlogSelection ($$) {
260   my ($name, $default) = @_;
261
262   $default ||= 'All';
263
264   my %values;
265
266   $values{All} = 'All';
267
268   $values{$$_{$name}} = $$_{$name}
269     for ($clearadm->FindAlertlog);
270
271   my $dropdown = popup_menu {
272     name    => $name,
273     class   => 'dropdown',
274     values  => [sort keys %values],
275     default => $default,
276   };
277
278   return $dropdown;
279 } # _makeAlertlogSelection
280
281 sub _makeRunlogSelection ($$) {
282   my ($name, $default) = @_;
283
284   $default ||= 'All';
285
286   my @values = sort $clearadm->GetUniqueList ('runlog', $name);
287
288   unshift @values, 'All';
289
290   my %values;
291
292   for (@values) {
293      unless ($_ eq '') {
294        $values{$_} = $_;
295      } else {
296        $values{NULL} = '<NULL>';
297      } #if
298   } # for
299
300   my $dropdown = popup_menu {
301     name    => $name,
302     class   => 'dropdown',
303     values  => \@values,
304     default => $default,
305     labels  => \%values,
306   };
307
308   return $dropdown;
309 } # _makeRunlogSelection
310
311 sub _makeRunlogSelectionNumeric ($$) {
312   my ($name, $default) = @_;
313
314   $default ||= 'All';
315
316   my @values = sort {$a <=> $b} $clearadm->GetUniqueList ('runlog', $name);
317
318   unshift @values, 'All';
319
320   my $dropdown = popup_menu {
321     name    => $name,
322     class   => 'dropdown',
323     values  => [@values],
324     default => $default,
325   };
326
327   return $dropdown;
328 } # _makeRunlogSelection
329
330 sub makeAlertDropdown (;$$) {
331   my ($label, $default) = @_;
332
333   $label ||= '';
334
335   my @values;
336
337   push @values, $$_{name}
338     for ($clearadm->FindAlert);
339
340   my $dropdown  = "$label ";
341      $dropdown .= popup_menu {
342     name    => 'alert',
343     class   => 'dropdown',
344     values  => [sort @values],
345     default => $default,
346   };
347
348   return $dropdown;
349 } # makeAlertDropdown
350
351 sub makeMultiplierDropdown (;$$) {
352   my ($label, $default) = @_;
353
354   $label ||= '';
355
356   my $dropdown  = "$label ";
357      $dropdown .= popup_menu {
358     name    => 'multiplier',
359     class   => 'dropdown',
360     values  => [sort @PREDEFINED_MULTIPLIERS],
361     default => $default,
362   };
363
364   return $dropdown;
365 } # makeMultiplierDropdown
366
367 sub makeNoMoreThanDropdown (;$$) {
368   my ($label, $default) = @_;
369
370   $label ||= '';
371
372   my $dropdown  = "$label ";
373      $dropdown .= popup_menu {
374     name    => 'nomorethan',
375     class   => 'dropdown',
376     values  => [sort @PREDEFINED_NOTMORETHAN],
377     default => $default,
378   };
379
380   return $dropdown;
381 } # makeNoMorThanDropdown
382
383 sub makeTagsDropdown($$) {
384   my ($type, $tag) = @_;
385
386   my $dropdown = ucfirst $type . ' ';
387
388   if ($type eq 'vob') {
389     my $vobs = Clearcase::Vobs->new;
390
391     $dropdown .= popup_menu {
392       name    => 'tag',
393       class   => 'dropdown',
394       values  => [sort $vobs->vobs],
395       default => $tag,
396     }; 
397   } else {
398     my $views = Clearcase::Views->new;
399
400     $dropdown .= popup_menu {
401       name    => 'tag',
402       class   => 'dropdown',
403       values  => [sort $views->views],
404       default => $tag,
405     };
406   } # if
407       
408   return span {id => $type}, $dropdown;
409 } # makeTagsDropdown
410
411 sub makeStoragePoolDropdown($$) {
412   my ($type, $tag) = @_;
413
414   my @values;
415
416   my $dropdown = 'Storage pool ';
417     
418   if ($type eq 'vob') {
419     push @values, qw(admin db cleartext derivedobj source total);
420   } else {
421     push @values, qw(admin db private total);
422   } # if
423
424   $dropdown .= popup_menu {
425     name    => 'storage',
426     class   => 'dropdown',
427     values  => \@values,
428     default => $tag,
429   };
430
431   return span {id => $type}, $dropdown;
432 } # makeStoragePoolsDropdown
433     
434 sub makeFilesystemDropdown ($;$$$) {
435   my ($system, $label, $default, $onchange) = @_;
436
437   $label ||= '';
438
439   my %filesystems;
440
441   for ($clearadm->FindFilesystem ($system)) {
442     my %filesystem = %{$_};
443
444     my $value = "$filesystem{filesystem} ($filesystem{mount})";
445
446     $filesystems{$filesystem{filesystem}} = $value;
447   } # for
448
449   my $dropdown .= "$label ";
450      $dropdown .= popup_menu {
451     name     => 'filesystem',
452     class    => 'dropdown',
453     values   => [sort keys %filesystems],
454     labels   => \%filesystems,
455     onChange => ($onchange) ? $onchange : '',
456     default  => $default,
457   };
458
459   return span {id => 'filesystems'}, $dropdown;
460 } # makeFilesystemDropdown
461
462 sub makeIntervalDropdown (;$$$) {
463   my ($label, $default, $onchange) = @_;
464
465   $label ||= '';
466
467   my @intervals = (
468     'Minute',
469     'Hour',
470     'Day',
471     'Month',
472   );
473
474   $default = ucfirst lc $default
475     if $default;
476
477   my $dropdown  = "$label ";
478      $dropdown .= popup_menu {
479     name     => 'scaling',
480     id       => 'scalingFactor',
481     class    => 'dropdown',
482     values   => [@intervals],
483     default  => $default,
484     onchange => $onchange,
485   };
486
487    return span {id => 'scaling'}, $dropdown;
488 } # makeIntervalDropdown;
489
490 sub makeNotificationDropdown (;$$) {
491   my ($label, $default) = @_;
492
493   $label ||= '';
494
495   my @values;
496
497   push @values, $$_{name}
498     for ($clearadm->FindNotification);
499
500   my $dropdown  = "$label ";
501      $dropdown .= popup_menu {
502     name    => 'notification',
503     class   => 'dropdown',
504     values  => [sort @values],
505     default => $default,
506   };
507
508   return $dropdown;
509 } # makeNotificationDropdown
510
511 sub makeRestartableDropdown (;$$) {
512   my ($label, $default) = @_;
513
514   $label ||= '';
515
516   my @values = (
517     'true',
518     'false',
519   );
520
521   my $dropdown  = "$label ";
522      $dropdown .= popup_menu {
523     name    => 'restartable',
524     class   => 'dropdown',
525     values  => [@values],
526     default => $default,
527   };
528
529   return $dropdown;
530 } # makeRestartableDropdown
531
532 sub makeSystemDropdown (;$$$%) {
533   my ($label, $default, $onchange, %systems) = @_;
534
535   $label ||= '';
536
537   for ($clearadm->FindSystem) {
538     my %system = %{$_};
539
540     my $value  = $system{name};
541        $value .= $system{alias} ? " ($system{alias})" : '';
542
543     $systems{$system{name}} = $value;
544   } # for
545
546   my $systemDropdown .= "$label ";
547      $systemDropdown .= popup_menu {
548        name     => 'system',
549        class    => 'dropdown',
550        values   => [sort keys %systems],
551        labels   => \%systems,
552        onchange => ($onchange) ? $onchange : '',
553        default  => $default,
554     };
555
556   return span {id => 'systems'}, $systemDropdown;
557 } # makeSystemDropdown
558
559 sub makeTaskDropdown (;$$) {
560   my ($label, $default) = @_;
561
562   $label ||= '';
563
564   my @values;
565
566   push @values, $$_{name}
567     for ($clearadm->FindTask);
568
569   my $taskDropdown  = "$label ";
570      $taskDropdown .= popup_menu {
571     name    => 'task',
572     class   => 'dropdown',
573     values  => [sort @values],
574     default => $default,
575   };
576
577   return $taskDropdown;
578 } # makeTaskDropdown
579
580 sub makeTimeDropdown ($$$;$$$$$) {
581   my (
582     $table,
583     $elementID,
584     $system,
585     $filesystem,
586     $label,
587     $default,
588     $interval,
589     $name,
590   ) = @_;
591
592   $label ||= '';
593
594   my @times;
595
596   $name ||= lc $label;
597
598   push @times, 'Earliest';
599
600   if ($table =~ /loadavg/i) {
601     push @times, $$_{timestamp}
602       for ($clearadm->GetLoadavg ($system, undef, undef, undef, $interval));
603   } elsif ($table =~ /filesystem/i) {
604     push @times, $$_{timestamp}
605       for ($clearadm->GetFS ($system, $filesystem, undef, undef, undef, $interval));
606   } # if
607
608   push @times, 'Latest';
609
610   unless ($default) {
611     $default = $name eq 'start' ? 'Earliest' : 'Latest';
612   } # unless
613
614   my $timeDropdown = "$label ";
615      $timeDropdown .= span {id => $elementID}, popup_menu {
616     name    => $name,
617     class   => 'dropdown',
618     values  => [@times],
619     default => $default,
620   };
621
622   return $timeDropdown;
623 } # makeTimeDropdown
624
625 sub heading (;$$) {
626   my ($title, $type) = @_;
627
628   if ($title) {
629     $title = "$APPNAME: $title";
630   } else {
631     $title = $APPNAME;
632   } # if
633
634   display header;
635   display start_html {
636         -title  => $title,
637         -author => 'Andrew DeFaria <Andrew@ClearSCM.com>',
638         -meta   => {
639           keywords  => 'ClearSCM Clearadm',
640       copyright => 'Copyright (c) ClearSCM, Inc. 2010, All rights reserved',
641         },
642         -script => [{
643           -language => 'JavaScript',
644           -src      => 'clearadm.js',
645         }],
646         -style   => ['clearadm.css', 'clearmenu.css'],
647   }, $title;
648
649   return if $type;
650
651   my $ieTableWrapStart = '<!--[if gt IE 6]><!--></a><!--<![endif]--><!--'
652                        . '[if lt IE 7]><table border="0" cellpadding="0" '
653                        . 'cellspacing="0"><tr><td><![endif]-->';
654   my $ieTableWrapEnd   = '<!--[if lte IE 6]></td></tr></table></a><![endif]-->';
655
656   # Menubar
657   display div {id=>'mastheadlogo'}, h1 {class => 'title'}, $APPNAME;
658   display start_div {class => 'menu'};
659
660   # Home
661   display ul li a {href => '/clearadm'}, 'Home';
662
663   my @allSystems = $clearadm->FindSystem;
664
665   # Systems
666   display start_ul;
667     display start_li;
668       display a {href => 'systems.cgi'}, "Systems$ieTableWrapStart";
669         display start_ul;
670           for (sort @allSystems) {
671             my %system = %{$_};
672             my $sysName  = ucfirst $system{name};
673                $sysName .= " ($system{alias})"
674                  if $system{alias};
675
676             display li a {
677               href => "systemdetails.cgi?system=$system{name}"
678             }, ucfirst "&nbsp;$sysName";
679           } # for
680         display end_ul;
681         display $ieTableWrapEnd;
682         display end_li;
683     display end_li;
684   display end_ul;
685
686   # Filesystems
687   display start_ul;
688     display start_li;
689       display a {href => 'filesystems.cgi'}, "Filesystems$ieTableWrapStart";
690         display start_ul;
691           for (@allSystems) {
692             my %system = %{$_};
693             my $sysName  = ucfirst $system{name};
694                $sysName .= " ($system{alias})"
695                  if $system{alias};
696
697             display li a {
698               href => "filesystems.cgi?system=$system{name}"
699             }, ucfirst "&nbsp;$sysName";
700           } # for
701         display end_ul;
702         display $ieTableWrapEnd;
703     display end_li;
704   display end_ul;
705
706   # Vobs
707   display start_ul;
708     display start_li;
709       display a {href => 'vobservers.cgi'}, "&nbsp;&nbsp;&nbsp;VOBs$ieTableWrapStart";
710       display $ieTableWrapEnd;
711     display end_li;
712   display end_ul;
713
714   # Views
715   display start_ul;
716     display start_li;
717       display a {href => 'viewager.cgi'}, "Views$ieTableWrapStart";
718       display $ieTableWrapEnd;
719     display end_li;
720   display end_ul;
721
722   # Configure
723   display start_ul;
724     display start_li;
725       display a {href => '#'}, "Configure$ieTableWrapStart";
726       display start_ul;
727         display li a {href => 'alerts.cgi'},        '&nbsp;Alerts';
728         display li a {href => 'notifications.cgi'}, '&nbsp;Notifications';
729         display li a {href => 'schedule.cgi'},      '&nbsp;Schedule';
730         display li a {href => 'tasks.cgi'},         '&nbsp;Tasks';
731       display end_ul;
732       display $ieTableWrapEnd;
733     display end_li;
734   display end_ul;
735
736   # Logs
737   display start_ul;
738     display start_li;
739       display a {href => '#'}, "Logs$ieTableWrapStart";
740       display start_ul;
741         display li a {href => 'alertlog.cgi'}, '&nbsp;Alert';
742         display li a {href => 'runlog.cgi'},   '&nbsp;Run';
743       display end_ul;
744       display $ieTableWrapEnd;
745     display end_li;
746   display end_ul;
747
748   # Help
749   display start_ul;
750     display start_li;
751       display a {href => '#'}, "Help$ieTableWrapStart";
752       display start_ul {class => 'rightmenu'};
753         display li a {href => 'readme.cgi'}, "&nbsp;About: $APPNAME $VERSION";
754       display end_ul;
755       display $ieTableWrapEnd;
756     display end_li;
757   display end_ul;
758   display end_div;
759
760   display start_div {class => 'page'};
761
762   return;
763 } # heading
764
765 sub displayAlert (;$) {
766   my ($alert) = @_;
767
768   display start_table {cellspacing => 1};
769
770   display start_Tr;
771     display th {class => 'labelCentered'}, 'Actions';
772     display th {class => 'labelCentered'}, 'Name';
773     display th {class => 'labelCentered'}, 'Type';
774     display th {class => 'labelCentered'}, 'Who';
775     display th {class => 'labelCentered'}, 'Category';
776   display end_Tr;
777
778   for ($clearadm->FindAlert ($alert)) {
779     my %alert = %{$_};
780
781     $alert{who} = setField $alert{who}, 'System Administrator';
782
783     display start_Tr;
784       my $areYouSure = "Are you sure you want to delete the $alert{name} alert?";
785
786       my $actions = start_form {
787         method => 'post',
788         action => 'processalert.cgi',
789       };
790
791       $actions .= input {
792         name   => 'name',
793         type   => 'hidden',
794         value  => $alert{name},
795       };
796
797       if (InArray $alert{name}, @PREDEFINED_ALERTS) {
798         $actions .= input {
799           name     => 'delete',
800           disabled => 'true',
801           type     => 'image',
802           src      => 'delete.png',
803           alt      => 'Delete',
804           value    => 'Delete',
805           title    => 'Cannot delete predefined alert',
806         };
807         $actions .= input {
808           name     => 'edit',
809           disabled => 'true',
810           type     => 'image',
811           src      => 'edit.png',
812           alt      => 'Edit',
813           value    => 'Edit',
814           title    => 'Cannot edit predefined alert',
815         };
816       } else {
817         $actions .= input {
818           name    => 'delete',
819           type    => 'image',
820           src     => 'delete.png',
821           alt     => 'Delete',
822           value   => 'Delete',
823           title   => 'Delete',
824           onclick => "return AreYouSure ('$areYouSure');",
825         };
826         $actions .= input {
827           name    => 'edit',
828           type    => 'image',
829           src     => 'edit.png',
830           alt     => 'Edit',
831           value   => 'Edit',
832           title   => 'Edit',
833         };
834       } # if
835
836       display end_form;
837
838       my $who = $alert{who};
839
840       if ($who =~ /^([a-zA-Z0-9._-]+)@([a-zA-Z0-9.-]+\.[a-zA-Z]{2,4})$/) {
841         $who = a {href => "mailto:$1\@$2"}, $who;
842       } # if
843
844       display td {class => 'dataCentered'}, $actions;
845       display td {class => 'data'},         $alert{name};
846       display td {class => 'data'},         $alert{type};
847       display td {class => 'data'},         $who;
848       display td {class => 'data'},
849         (InArray $alert{name}, @PREDEFINED_ALERTS) ? 'Predefined' : 'User Defined';
850     display end_Tr;
851   } # for
852
853   display end_table;
854
855   display p {class => 'center'}, a {
856     href => 'processalert.cgi?action=Add',
857   }, 'New alert ', img {
858     src    => 'add.png',
859     border => 0,
860   };
861
862   return;
863 } # DisplayAlerts
864
865 sub displayAlertlog (%) {
866   my (%opts) = @_;
867
868   my $optsChanged;
869
870   unless (($opts{oldalert}        and $opts{alert}         and
871            $opts{oldalert}        eq  $opts{alert})        and
872           ($opts{oldsystem}       and $opts{system}        and
873            $opts{oldsystem}       eq  $opts{system})       and
874           ($opts{oldnotification} and $opts{notification}  and
875            $opts{oldnotification} eq  $opts{notification})) {
876     $optsChanged = 1;
877   } # unless
878
879   my $condition;
880
881   unless ($opts{id}) {
882     $condition  = "alert like '%";
883     $condition .= $opts{alert} ? $opts{alert} : '';
884     $condition .= "%'";
885     $condition .= ' and ';
886     $condition .= "system like '%";
887     $condition .= $opts{system} ? $opts{system} : '';
888     $condition .= "%'";
889     $condition .= ' and ';
890     $condition .= "notification like '%";
891     $condition .= $opts{notification} ? $opts{notification} : '';
892     $condition .= "%'";
893   } # unless
894
895   my $total = $clearadm->Count ('alertlog', $condition);
896
897   if ($opts{'nextArrow.x'}) {
898     $opts{start} = $opts{next};
899   } elsif ($opts{'prevArrow.x'}) {
900     $opts{start} = $opts{prev};
901   } else {
902     $opts{start} = 0;
903   } # if
904
905   my $next = $opts{start} + $opts{page} < $total
906            ? $opts{start} + $opts{page}
907            : $opts{start};
908   my $prev = $opts{start} - $opts{page} >= 0
909            ? $opts{start} - $opts{page}
910            : $opts{start};
911
912   my $opts  = $opts{start} + 1;
913      $opts .= '-';
914      $opts .= $opts{start} + $opts{page} < $total
915             ? $opts{start} + $opts{page}
916             : $total;
917      $opts .= " of $total";
918
919   display start_form {
920     method => 'post',
921     action => 'alertlog.cgi'
922   };
923
924   # Hidden fields to pass along
925   display input {name  => 'prev', type  => 'hidden', value => $prev};
926   display input {name  => 'next', type  => 'hidden', value => $next};
927
928   display input {
929     name  => 'oldalert',
930     type  => 'hidden',
931     value => $opts{alert},
932   };
933   display input {
934     name  => 'oldsystem',
935     type  => 'hidden',
936     value => $opts{system},
937   };
938   display input {
939     name  => 'oldnotification',
940     type  => 'hidden',
941     value => $opts{notification},
942   };
943
944   my $caption = start_table {
945     class       => 'caption',
946     cellspacing => 1,
947     width       => '100%',
948   };
949
950   $caption .= start_Tr;
951
952     unless ($opts{id}) {
953       $caption .= td {align => 'left'}, input {
954         name     => 'prevArrow',
955         type     => 'image',
956         src      => 'left.png',
957         alt      => 'Previous',
958         value    => 'prev',
959       };
960     } else {
961       $caption .= td {align => 'left'}, img {
962         src      => 'left.png',
963         disabled => 'disabled',
964       };
965     } # unless
966
967     $caption .= td {align => 'center'}, $opts;
968
969     unless ($opts{id}) {
970       $caption .= td {align => 'right'}, input {
971         name     => 'nextArrow',
972         type     => 'image',
973         src      => 'right.png',
974         alt      => 'Next',
975         value    => 'next',
976       };
977     } else {
978       $caption .= td {align => 'right'}, img {
979         src      => 'right.png',
980         disabled => 'disabled',
981       };
982     } # unless
983
984   $caption .= end_Tr;
985
986   $caption .= end_table;
987
988   display start_table {cellspacing => 1, width => '98%'};
989
990   display caption $caption;
991
992   display start_Tr;
993     display th {class => 'labelCentered'}, '#';
994     display th {class => 'labelCentered'}, 'Delete';
995     display th {class => 'labelCentered'}, 'Name';
996     display th {class => 'labelCentered'}, 'System';
997     display th {class => 'labelCentered'}, 'Notification';
998     display th {class => 'labelCentered'}, 'Date/Time';
999     display th {class => 'labelCentered'}, 'Runlog';
1000     display th {class => 'labelCentered'}, 'Message';
1001   display end_Tr;
1002
1003   display start_Tr;
1004     display td {
1005       class   => 'filter',
1006       align   => 'right',
1007       colspan => 2,
1008     }, b 'Filter:';
1009     display td {
1010       class => 'filter'
1011     }, _makeAlertlogSelection ('alert', $opts{alert});
1012     display td {
1013       class => 'filter'
1014     }, _makeAlertlogSelection ('system', $opts{system});
1015     display td {
1016       class => 'filter'
1017     }, _makeAlertlogSelection ('notification', $opts{notification});
1018     display td {
1019       class => 'filter',
1020     }, input {
1021       type  => 'submit',
1022       value => 'Update',
1023     };
1024     display end_form;
1025     display td {
1026       class   => 'filter',
1027       align   => 'center',
1028       colspan => 2,
1029     # TODO: Would like to have Clear All Alerts be Clear Alerts and for it to
1030     # clear only the alerts that have been filtered.
1031     }, a {
1032         href => 'deletealertlog.cgi?alertlogid=all'
1033     }, input {
1034       type    => 'button',
1035       value   => 'Clear All Events',
1036       onclick => "return AreYouSure('Are you sure you want to delete all alerts?');",
1037     };
1038   display end_Tr;
1039
1040   my $i = $opts{start};
1041
1042   for ($clearadm->FindAlertlog (
1043     $opts{alert},
1044     $opts{system},
1045     $opts{notification},
1046     $opts{start},
1047     $opts{page},
1048     )) {
1049     my %alertlog = setFields 'N/A', %{$_};
1050
1051     display start_Tr;
1052       my %system = $clearadm->GetSystem ($alertlog{system});
1053
1054       display td {class => 'dataCentered'}, ++$i;
1055       display td {class => 'dataCentered'}, a {
1056         href => "deletealertlog.cgi?alertlogid=$alertlog{id}"
1057       }, img {
1058         src => 'delete.png',
1059         alt     => 'Delete',
1060         title   => 'Delete',
1061         border  => 0,
1062         onclick => "return AreYouSure ('Are you sure you wish to delete this alertlog entry?');",
1063       };
1064       display td {class => 'data'}, a {
1065         href => "alerts.cgi?alert=$alertlog{alert}"
1066       }, $alertlog{alert};
1067       display td {class => 'data'}, a {
1068         href => "systemdetails.cgi?system=$alertlog{system}"
1069       }, $alertlog{system};
1070       display td {class => 'data'}, a {
1071         href => "notifications.cgi?notification=$alertlog{notification}"
1072       }, $alertlog{notification};
1073       display td {class => 'data'},         $alertlog{timestamp};
1074       display td {class => 'dataCentered'}, a {
1075         href => "runlog.cgi?id=$alertlog{runlog}"
1076       }, $alertlog{runlog};
1077       display td {class => 'data'},         $alertlog{message};
1078     display end_Tr;
1079   } # for
1080
1081   display end_form;
1082
1083   display end_table;
1084
1085   return;
1086 } # displayAlertlog
1087
1088 sub displayFilesystem ($) {
1089   my ($systemName) = @_;
1090
1091   display start_table {cellspacing => 1, width => '98%'};
1092
1093   display start_Tr;
1094     display th {class => 'labelCentered'}, 'Action';
1095     display th {class => 'labelCentered'}, 'Name';
1096     display th {class => 'labelCentered'}, 'Alias';
1097     display th {class => 'labelCentered'}, 'Admin';
1098     display th {class => 'labelCentered'}, 'Filesystem';
1099     display th {class => 'labelCentered'}, 'Mount';
1100     display th {class => 'labelCentered'}, 'Type';
1101     display th {class => 'labelCentered'}, 'History';
1102     display th {class => 'labelCentered'}, 'Used';
1103     display th {class => 'labelCentered'}, 'Threshold';
1104     display th {class => 'labelCentered'}, 'Usage';
1105   display end_Tr;
1106
1107   for (sort { $a->{mount} cmp $b->{mount} } $clearadm->FindSystem ($systemName)) {
1108     my %system = %{$_};
1109
1110     %system = setFields ('N/A', %system);
1111
1112     my $admin = ($system{email} !~ 'N/A')
1113               ? a {-href => "mailto:$system{email}"}, $system{admin}
1114               : $system{admin};
1115
1116     for ($clearadm->FindFilesystem ($system{name})) {
1117       my %filesystem = %{$_};
1118
1119       my %fs = $clearadm->GetLatestFS ($system{name}, $filesystem{filesystem});
1120
1121       my $size = autoScale $fs{size};
1122       my $used = autoScale $fs{used};
1123       my $free = autoScale $fs{free};
1124
1125       # TODO: Note that this percentages does not agree with df output. I'm not
1126       # sure why.
1127       my $usedPct = $fs{size} == 0 ? 0
1128                   : sprintf ('%.0f',
1129                      (($fs{reserve} + $fs{used}) / $fs{size} * 100));
1130
1131       my $alias = ($system{alias} !~ 'N/A')
1132                 ? a {
1133                     href => "systemdetails.cgi?system=$system{name}"
1134                   }, $system{alias}
1135                 : $system{alias};
1136
1137       my $class         = $usedPct < $filesystem{threshold}
1138                         ? 'data'
1139                         : 'dataAlert';
1140       my $classRight    = $usedPct < $filesystem{threshold}
1141                         ? 'dataRight'
1142                         : 'dataRightAlert';
1143       my $classCentered = $usedPct < $filesystem{threshold}
1144                         ? 'dataCentered'
1145                         : 'dataCenteredAlert';
1146       my $classRightTop = $usedPct < $filesystem{threshold}
1147                         ? 'dataRightTop'
1148                         : 'dataRightAlertTop';
1149
1150       display start_Tr;
1151         display start_td {class => 'dataCentered'};
1152
1153         my $areYouSure = 'Are you sure you want to delete '
1154                        . "$system{name}:$filesystem{filesystem}?" . '\n'
1155                        . 'Doing so will remove all records related to this\n'
1156                        . 'filesystem and its history.';
1157
1158         display start_form {
1159           method => 'post',
1160           action => "processfilesystem.cgi",
1161         };
1162
1163         display input {
1164           type  => 'hidden',
1165           name  => 'system',
1166           value => $system{name},
1167         };
1168         display input {
1169           type  => 'hidden',
1170           name  => 'filesystem',
1171           value => $filesystem{filesystem},
1172         };
1173
1174         display input {
1175           name    => 'delete',
1176           type    => 'image',
1177           src     => 'delete.png',
1178           alt     => 'Delete',
1179           value   => 'Delete',
1180           title   => 'Delete',
1181           onclick => "return AreYouSure ('$areYouSure');"
1182         };
1183         display input {
1184           name    => 'edit',
1185           type    => 'image',
1186           src     => 'edit.png',
1187           alt     => 'Edit',
1188           value   => 'Edit',
1189           title   => 'Edit',
1190         };
1191
1192         if ($filesystem{notification}) {
1193           display a {
1194             href => "alertlog.cgi?system=$filesystem{system}"}, img {
1195             src    => 'alert.png',
1196             border => 0,
1197             alt    => 'Alert!',
1198             title  => 'This filesystem has alerts',
1199           };
1200         } # if
1201
1202         display end_form;
1203
1204         display end_td;
1205         display td {class => $class},
1206           a {-href => "systemdetails.cgi?system=$system{name}"}, $system{name};
1207         display td {class => $class}, $alias;
1208         display td {class => $class}, $admin;
1209         display td {class => $class}, $filesystem{filesystem};
1210         display td {class => $class}, $filesystem{mount};
1211         display td {class => $class}, $filesystem{fstype};
1212         display td {class => $classCentered}, $filesystem{filesystemHist};
1213         display td {class => $classRightTop}, "$used ($usedPct%)<br>",
1214           font {class => 'unknown'}, "$fs{timestamp}";
1215         display td {class => $classRightTop}, "$filesystem{threshold}%";
1216         display td {class => $class},
1217           a {href =>
1218             "plot.cgi?type=filesystem&system=$system{name}"
1219           . "&filesystem=$filesystem{filesystem}&scaling=Day&points=7"
1220           }, img {
1221             src    => "plotfs.cgi?system=$system{name}"
1222                     . "&filesystem=$filesystem{filesystem}&tiny=1",
1223             border => 0,
1224           };
1225       display end_Tr;
1226     } # for
1227   } # for
1228
1229   display end_table;
1230
1231   return;
1232 } # displayFilesystem
1233
1234 sub displayNotification (;$) {
1235   my ($notification) = @_;
1236
1237   display start_table {cellspacing => 1};
1238
1239   display start_Tr;
1240     display th {class => 'labelCentered'}, 'Actions';
1241     display th {class => 'labelCentered'}, 'Name';
1242     display th {class => 'labelCentered'}, 'Alert';
1243     display th {class => 'labelCentered'}, 'Condition';
1244     display th {class => 'labelCentered'}, 'Not More Than';
1245     display th {class => 'labelCentered'}, 'Category';
1246   display end_Tr;
1247
1248   for ($clearadm->FindNotification ($notification)) {
1249     my %notification= setFields 'N/A', %{$_};
1250
1251     display start_Tr;
1252     my $areYouSure = "Are you sure you want to delete the $notification{name} "
1253                    . 'notification?';
1254
1255     my $actions = start_form {
1256       method => 'post',
1257       action => 'processnotification.cgi',
1258     };
1259
1260     $actions .= input {
1261       name   => 'name',
1262       type   => 'hidden',
1263       value  => $notification{name},
1264     };
1265
1266     if (InArray $notification{name}, @PREDEFINED_NOTIFICATIONS) {
1267       $actions .= input {
1268         name     => 'delete',
1269         disabled => 'true',
1270         type     => 'image',
1271         src      => 'delete.png',
1272         alt      => 'Delete',
1273         value    => 'Delete',
1274         title    => 'Cannot delete predefined notification',
1275       };
1276       $actions .= input {
1277         name     => 'edit',
1278         disabled => 'true',
1279         type     => 'image',
1280         src      => 'edit.png',
1281         alt      => 'Edit',
1282         value    => 'Edit',
1283         title    => 'Cannot edit predefined notification',
1284       };
1285     } else {
1286       $actions .= input {
1287         name    => 'delete',
1288         type    => 'image',
1289         src     => 'delete.png',
1290         alt     => 'Delete',
1291         value   => 'Delete',
1292         title   => 'Delete',
1293         onclick => "return AreYouSure ('$areYouSure');",
1294       };
1295       $actions .= input {
1296         name    => 'edit',
1297         type    => 'image',
1298         src     => 'edit.png',
1299         alt     => 'Edit',
1300         value   => 'Edit',
1301         title   => 'Edit',
1302       };
1303     } # if
1304
1305     display end_form;
1306
1307     display td {class => 'dataCentered'}, $actions;
1308     display td {class => 'data'},         $notification{name};
1309     display td {class => 'data'},         a {
1310       href => "alerts.cgi?alert=$notification{alert}"
1311     }, $notification{alert};
1312     display td {class => 'data'},         $notification{cond};
1313     display td {class => 'data'},         $notification{nomorethan};
1314     display td {class => 'data'},
1315       (InArray $notification{name}, @PREDEFINED_NOTIFICATIONS)
1316       ? 'Predefined'
1317       : 'User Defined';
1318
1319     display end_Tr;
1320   } # for
1321
1322   display end_table;
1323
1324   display p {class => 'center'}, a {
1325     href => 'processnotification.cgi?action=Add',
1326   }, 'New notification', img {
1327     src    => 'add.png',
1328     border => 0,
1329   };
1330
1331   return;
1332 } # displayNotification
1333
1334 sub displayRunlog (%) {
1335   my (%opts) = @_;
1336
1337   my $optsChanged;
1338
1339   for (qw(task system not status)) {
1340     my $old = "old$_";
1341     if (($opts{$old} and $opts{$_}) and ($opts{$old} ne $opts{$_})) {
1342       $optsChanged = 1;
1343       last;
1344     } # if
1345   } # for
1346
1347   my $condition = '';
1348
1349   unless ($opts{id}) {
1350     if ($opts{task} !~ /all/i) {
1351       $condition  = "task like '%";
1352       $condition .= $opts{task} ? $opts{task} : '';
1353       $condition .= "%'";
1354     } # if
1355
1356     if ($opts{system} !~ /all/i) {
1357       if ($opts{system} eq '<NULL>') {
1358         $condition .= ' and system is null';
1359         undef $opts{system}
1360       } elsif ($opts{system} ne 'All') {
1361         $condition .= " and system like '%$opts{system}%'";;
1362       } # if
1363     } # if
1364
1365     if ($opts{status} !~ /all/i) {
1366       $condition .= ' and ';
1367       unless ($opts{not}) {
1368         $condition .= "status=$opts{status}";
1369       } else {
1370         $condition .= "status<>$opts{status}";
1371       } # unless
1372     } # if
1373   } # unless
1374
1375   my $total = $clearadm->Count ('runlog', $condition);
1376
1377   $opts{start} = $opts{'nextArrow.x'} ? $opts{next} : $opts{prev};
1378   $opts{start} ||= 0;
1379   $opts{start} = 0
1380     if $optsChanged;
1381
1382   my $next = $opts{start} + $opts{page} < $total
1383            ? $opts{start} + $opts{page}
1384            : $opts{start};
1385   my $prev = $opts{start} - $opts{page} >= 0
1386            ? $opts{start} - $opts{page}
1387            : $opts{start};
1388
1389   my $opts  = $opts{'nextArrow.x'} ? $opts{next} + 1 : $opts{prev} + 1;
1390      $opts .= '-';
1391      $opts .= $opts{start} + $opts{page} < $total
1392             ? $opts{start} + $opts{page}
1393             : $total;
1394      $opts .= " of $total";
1395
1396   display start_form {
1397     method => 'post',
1398     action => 'runlog.cgi'
1399   };
1400
1401   # Hidden fields to pass along
1402   display input {name => 'prev',      type => 'hidden', value => $prev};
1403   display input {name => 'next',      type => 'hidden', value => $next};
1404   display input {name => 'oldtask',   type => 'hidden', value => $opts{task}};
1405   display input {name => 'oldsystem', type => 'hidden', value => $opts{system}};
1406   display input {name => 'oldnot',    type => 'hidden', value => $opts{not}};
1407   display input {name => 'oldstatus', type => 'hidden', value => $opts{status}};
1408
1409   my $caption = start_table {
1410     class       => 'caption',
1411     cellspacing => 1,
1412     width       => '100%',
1413   };
1414
1415   $caption .= start_Tr;
1416
1417   unless ($opts{id}) {
1418     $caption .= td {align => 'left'}, input {
1419       name     => 'prevArrow',
1420       type     => 'image',
1421       src      => 'left.png',
1422       alt      => 'Previous',
1423       value    => 'prev',
1424     };
1425   } else {
1426     $caption .= td {align => 'left'}, img {
1427       src      => 'left.png',
1428       disabled => 'disabled',
1429     };
1430   } # unless
1431
1432   $caption .= td {align => 'center'}, $opts;
1433
1434   unless ($opts{id}) {
1435     $caption .= td {align => 'right'}, input {
1436       name     => 'nextArrow',
1437       type     => 'image',
1438       src      => 'right.png',
1439       alt      => 'Next',
1440       value    => 'next',
1441     };
1442   } else {
1443     $caption .= td {align => 'right'}, img {
1444       src      => 'right.png',
1445       disabled => 'disabled',
1446     };
1447   } # unless
1448
1449   $caption .= end_Tr;
1450
1451   $caption .= end_table;
1452
1453   display start_table {cellspacing => 1, width => '98%'};
1454
1455   display caption $caption;
1456
1457   display start_Tr;
1458     display th {class => 'labelCentered'}, '#';
1459     display th {class => 'labelCentered'}, 'ID';
1460     display th {class => 'labelCentered'}, 'Task';
1461     display th {class => 'labelCentered'}, 'System';
1462     display th {class => 'labelCentered'}, 'Started';
1463     display th {class => 'labelCentered'}, 'Ended';
1464     display th {class => 'labelCentered'}, 'Status';
1465     display th {class => 'labelCentered'}, 'Message';
1466   display end_Tr;
1467
1468   display start_Tr;
1469     $opts{not} ||= 'false';
1470
1471     display start_form {
1472       method => 'post',
1473       action => 'runlog.cgi'
1474     };
1475     display td {
1476       class   => 'filter',
1477       align   => 'right',
1478       colspan => 2,
1479     }, b 'Filter:';
1480     display td {
1481       class => 'filter'
1482     }, _makeRunlogSelection ('task', $opts{task});
1483     display td {
1484       class => 'filter'
1485     }, _makeRunlogSelection ('system', $opts{system});
1486     display td {class => 'filter'}, '&nbsp;';
1487     display td {
1488       class => 'filter',
1489       align => 'right',
1490     }, "Not: ", checkbox {
1491       name    => 'not',
1492       value   => 'true',
1493       checked => $opts{not} eq 'true' ? 1 : 0,
1494       label   => '',
1495     };
1496     display td {
1497       class => 'filter'
1498     }, _makeRunlogSelectionNumeric ('status', $opts{status});
1499     display td {
1500       class => 'filter',
1501     }, input {
1502       type  => 'submit',
1503       value => 'Update',
1504     };
1505
1506     display end_form;
1507   display end_Tr;
1508
1509   my $i = $opts{start};
1510
1511   my $status;
1512
1513   if ($opts{status}) {
1514     if ($opts{status} !~ /all/i) {
1515       $status = $opts{not} ne 'true' ? $opts{status} : "!$opts{status}";
1516     } # if
1517   } # if
1518
1519   for ($clearadm->FindRunlog (
1520     $opts{task},
1521     $opts{system},
1522     $status,
1523     $opts{id},
1524     $opts{start},
1525     $opts{page},
1526     )) {
1527     my %runlog = setFields 'N/A', %{$_};
1528
1529     my $class         = $runlog{status} == 0
1530                       ? 'data'
1531                       : 'dataAlert';
1532     my $classCentered = $runlog{status} == 0
1533                       ? 'dataCentered'
1534                       : 'dataAlertCentered';
1535     my $classRight    = $runlog{status} == 0
1536                       ? 'dataRight'
1537                       : 'dataAlertRight';
1538
1539     display start_Tr;
1540       display td {class => 'dataCentered'}, ++$i;
1541       display td {class => 'dataCentered'}, $runlog{id};
1542       display td {class => 'data'},         a {
1543         href => "tasks.cgi?task=$runlog{task}"
1544       }, $runlog{task};
1545       display td {class => 'data'}, $runlog{system} eq 'localhost'
1546         ? $runlog{system}
1547         : a {
1548         href => "systemdetails.cgi?system=$runlog{system}"
1549       }, $runlog{system};
1550       display td {class => 'dataCentered'}, $runlog{started};
1551       display td {class => 'dataCentered'}, $runlog{ended};
1552       display td {class => $classRight},    $runlog{status};
1553
1554       my $message = $runlog{message};
1555          $message =~ s/\r\n/<br>/g;
1556
1557       display td {class => $class, width => '50%'},         $message;
1558     display end_Tr;
1559   } # for
1560
1561   display end_table;
1562
1563   return;
1564 } # displayRunlog
1565
1566 sub displaySchedule () {
1567   display start_table {cellspacing => 1};
1568
1569   display start_Tr;
1570     display th {class => 'labelCentered'}, 'Actions';
1571     display th {class => 'labelCentered'}, 'Active';
1572     display th {class => 'labelCentered'}, 'Name';
1573     display th {class => 'labelCentered'}, 'Task';
1574     display th {class => 'labelCentered'}, 'Notification';
1575     display th {class => 'labelCentered'}, 'Frequency';
1576     display th {class => 'labelCentered'}, 'Category';
1577   display end_Tr;
1578
1579   for ($clearadm->FindSchedule) {
1580     my %schedule = setFields 'N/A', %{$_};
1581
1582     display start_Tr;
1583     my $areYouSure = "Are you sure you want to delete the $schedule{name} "
1584                    . "schedule?";
1585
1586     my $actions = start_form {
1587       method => 'post',
1588       action => 'processschedule.cgi',
1589     };
1590
1591     $actions .= input {
1592       name   => 'name',
1593       type   => 'hidden',
1594       value  => $schedule{name},
1595     };
1596
1597     if (InArray $schedule{name}, @PREDEFINED_SCHEDULES) {
1598       $actions .= input {
1599         name     => 'delete',
1600         disabled => 'true',
1601         type     => 'image',
1602         src      => 'delete.png',
1603         alt      => 'Delete',
1604         value    => 'Delete',
1605         title    => 'Cannot delete predefined schedule',
1606       };
1607       $actions .= input {
1608         name     => 'edit',
1609         disabled => 'true',
1610         type     => 'image',
1611         src      => 'edit.png',
1612         alt      => 'Edit',
1613         value    => 'Edit',
1614         title    => 'Cannot edit predefined schedule',
1615       };
1616     } else {
1617       $actions .= input {
1618         name    => 'delete',
1619         type    => 'image',
1620         src     => 'delete.png',
1621         alt     => 'Delete',
1622         value   => 'Delete',
1623         title   => 'Delete',
1624         onclick => "return AreYouSure ('$areYouSure');",
1625       };
1626       $actions .= input {
1627         name    => 'edit',
1628         type    => 'image',
1629         src     => 'edit.png',
1630         alt     => 'Edit',
1631         value   => 'Edit',
1632         title   => 'Edit',
1633       };
1634     } # if
1635
1636     display end_form;
1637
1638     display td {class => 'dataCentered'}, $actions;
1639     display td {class => 'dataCentered'}, checkbox {
1640       disabled => 'disabled',
1641       checked  => $schedule{active} eq 'true' ? 1 : 0,
1642     };
1643     display td {class => 'data'},         $schedule{name};
1644     display td {class => 'data'},         a {
1645       href => "tasks.cgi?task=$schedule{task}"
1646     }, $schedule{task};
1647     display td {class => 'data'},         a {
1648       href => "notifications.cgi?notification=$schedule{notification}"
1649     }, $schedule{notification};
1650     display td {class => 'data'},         $schedule{frequency};
1651     display td {class => 'data'},
1652       (InArray $schedule{name}, @PREDEFINED_SCHEDULES)
1653         ? 'Predefined'
1654         : 'User Defined';
1655
1656     display end_Tr;
1657   } # for
1658
1659   display end_table;
1660
1661   display p {class => 'center'}, a {
1662     href => 'processschedule.cgi?action=Add',
1663   }, 'New schedule', img {
1664     src    => 'add.png',
1665     border => 0,
1666   };
1667
1668   return;
1669 } # displaySchedule
1670
1671 sub displaySystem ($) {
1672   my ($systemName) = @_;
1673
1674   my %system = $clearadm->GetSystem ($systemName);
1675
1676   unless (%system) {
1677     displayError "Nothing known about system $systemName";
1678     return;
1679   } # unless
1680
1681   my $lastheardfromClass = 'dataCentered';
1682   my $lastheardfromData  = $system{lastheardfrom};
1683
1684   my %load = $clearadm->GetLatestLoadavg ($systemName);
1685
1686   unless ($clearadm->SystemAlive (%system)) {
1687     $lastheardfromClass = 'dataCenteredAlert';
1688     $lastheardfromData  = a {
1689       href  => "alertlog.cgi?system=$system{name}",
1690       class => 'alert',
1691       title => "Have not heard from $system{name} for a while"
1692     }, $system{lastheardfrom};
1693     $system{notification} = 'Heartbeat';
1694   } # unless
1695
1696   my $admin = ($system{email})
1697             ? a {-href => "mailto:$system{email}"}, $system{admin}
1698             : $system{admin};
1699
1700   $system{alias}  = setField $system{alias},  'N/A';
1701   $system{region} = setField $system{region}, 'N/A';
1702
1703   display start_table {cellspacing => 1};
1704
1705   display start_Tr;
1706     my $areYouSure = 'Are you sure you want to delete this system?\n'
1707                    . "Doing so will remove all records related to $system{name}"
1708                    . '\nincluding filesystem records and history as well as '
1709                    . 'loadavg history.';
1710
1711     my $actions = start_form {
1712       method => 'post',
1713       action => 'processsystem.cgi',
1714     };
1715
1716     $actions .= input {
1717       name   => 'name',
1718       type   => 'hidden',
1719       value  => $system{name},
1720     };
1721
1722     $actions .= input {
1723       name    => 'delete',
1724       type    => 'image',
1725       src     => 'delete.png',
1726       alt     => 'Delete',
1727       value   => 'Delete',
1728       title   => 'Delete',
1729       onclick => "return AreYouSure ('$areYouSure');",
1730     };
1731     $actions .= input {
1732       name    => 'edit',
1733       type    => 'image',
1734       src     => 'edit.png',
1735       alt     => 'Edit',
1736       value   => 'Edit',
1737       title   => 'Edit',
1738     };
1739     $actions .= checkbox {
1740       disabled => 'disabled',
1741       checked  => $system{active} eq 'true' ? 1 : 0,
1742     };
1743
1744     if ($system{notification}) {
1745       $actions .= a {
1746         href => "alertlog.cgi?system=$system{name}"}, img {
1747         src    => 'alert.png',
1748         border => 0,
1749         alt    => 'Alert!',
1750         title  => 'This system has alerts',
1751       };
1752     } # if
1753
1754     display th {class => 'label'},                      "$actions Name:";
1755     display end_form;
1756     display td {class => 'dataCentered', colspan => 2}, $system{name};
1757     display th {class => 'label'},                      'Alias:';
1758     display td {class => 'dataCentered'},               $system{alias};
1759     display th {class => 'label'},                      'Admin:';
1760     display td {class => 'dataCentered', colspan => 2}, $admin;
1761     display th {class => 'label', colspan => 2},        'Type:';
1762     display td {class => 'dataCentered'},               $system{type};
1763   display end_Tr;
1764
1765   display start_Tr;
1766     display th {class => 'label'},               'OS Version:';
1767     display td {class => 'data', colspan => 10}, $system{os};
1768   display end_Tr;
1769
1770   display start_Tr;
1771     display th {class => 'label'}, 'Last Contacted:';
1772     display td {
1773       class => $lastheardfromClass,
1774       colspan => 2
1775     }, "$lastheardfromData ",
1776       font {class => 'dim' }, "<br>Up: $load{uptime}";
1777     display th {class => 'label'},        'Port:';
1778     display td {class => 'dataCentered'}, $system{port};
1779     display th {class => 'label'},        'Threshold:';
1780     display td {class => 'dataCentered'}, $system{loadavgThreshold};
1781     display th {class => 'label'},        'History:';
1782     display td {class => 'dataCentered'}, $system{loadavgHist};
1783     display th {class => 'label'},        'Load Avg:';
1784     display td {class => 'data'},
1785       a {href =>
1786         "plot.cgi?type=loadavg&system=$system{name}&scaling=Hour&points=24"
1787         }, img {
1788           src    => "plotloadavg.cgi?system=$system{name}&tiny=1",
1789           border => 0,
1790       };
1791
1792   my $description = $system{description};
1793   $description =~ s/\r\n/<br>/g;
1794
1795   display start_Tr;
1796     display th {class => 'label'},               'Description:';
1797     display td {class => 'data', colSpan => 10}, $description;
1798   display end_Tr;
1799
1800   display end_table;
1801
1802   display p {class => 'center'}, a {
1803     href => 'processsystem.cgi?action=Add',
1804   }, 'New system', img {
1805     src    => 'add.png',
1806     border => 0,
1807   };
1808
1809   display h1 {class => 'center'},
1810     'Filesystem Details: ' . ucfirst $system{name};
1811
1812   display start_table {cellspacing => 1};
1813
1814   display start_Tr;
1815     display th {class => 'labelCentered'}, 'Action';
1816     display th {class => 'labelCentered'}, 'Filesystem';
1817     display th {class => 'labelCentered'}, 'Type';
1818     display th {class => 'labelCentered'}, 'Mount';
1819     display th {class => 'labelCentered'}, 'Size';
1820     display th {class => 'labelCentered'}, 'Used';
1821     display th {class => 'labelCentered'}, 'Free';
1822     display th {class => 'labelCentered'}, 'Used %';
1823     display th {class => 'labelCentered'}, 'Threshold';
1824     display th {class => 'labelCentered'}, 'History';
1825     display th {class => 'labelCentered'}, 'Usage';
1826   display end_Tr;
1827
1828   for ($clearadm->FindFilesystem ($system{name})) {
1829     my %filesystem = %{$_};
1830
1831     my %fs = $clearadm->GetLatestFS (
1832       $filesystem{system},
1833       $filesystem{filesystem}
1834     );
1835
1836     my $size = autoScale $fs{size};
1837     my $used = autoScale $fs{used};
1838     my $free = autoScale $fs{free};
1839
1840     # TODO: Note that this percentages does not agree with df output. I'm not
1841     # sure why.
1842     my $usedPct = $fs{size} == 0 ? 0
1843                 : sprintf ('%.0f',
1844                    (($fs{reserve} + $fs{used}) / $fs{size} * 100));
1845
1846     my $class         = $usedPct < $filesystem{threshold}
1847                       ? 'data'
1848                       : 'dataAlert';
1849     my $classCentered = $class . 'Centered';
1850     my $classRight    = $class . 'Right';
1851
1852     display start_Tr;
1853         display start_td {class => 'data'};
1854
1855         my $areYouSure = 'Are you sure you want to delete '
1856                        . "$system{name}:$filesystem{filesystem}?" . '\n'
1857                        . 'Doing so will remove all records related to this\n'
1858                        . 'filesystem and its history.';
1859
1860         display start_form {
1861           method => 'post',
1862           action => 'processfilesystem.cgi',
1863         };
1864
1865         display input {
1866           type  => 'hidden',
1867           name  => 'system',
1868           value => $system{name},
1869         };
1870         display input {
1871           type  => 'hidden',
1872           name  => 'filesystem',
1873           value => $filesystem{filesystem},
1874         };
1875
1876         display input {
1877           name    => 'delete',
1878           type    => 'image',
1879           src     => 'delete.png',
1880           alt     => 'Delete',
1881           value   => 'Delete',
1882           title   => 'Delete',
1883           onclick => "return AreYouSure ('$areYouSure');"
1884         };
1885         display input {
1886           name    => 'edit',
1887           type    => 'image',
1888           src     => 'edit.png',
1889           alt     => 'Edit',
1890           value   => 'Edit',
1891           title   => 'Edit',
1892         };
1893
1894         if ($filesystem{notification}) {
1895           display a {
1896             href => "alertlog.cgi?system=$filesystem{system}"}, img {
1897             src    => 'alert.png',
1898             border => 0,
1899             alt    => 'Alert!',
1900             title  => 'This filesystem has alerts',
1901           };
1902         } # if
1903
1904         display end_form;
1905       display td {class => $class},         $filesystem{filesystem};
1906       display td {class => $classCentered}, $filesystem{fstype};
1907       display td {class => $class},         $filesystem{mount};
1908       display td {class => $classRight},    $size;
1909       display td {class => $classRight},    $used;
1910       display td {class => $classRight},    $free;
1911       display td {class => $classRight},    "$usedPct%";
1912       display td {class => $classRight},    "$filesystem{threshold}%";
1913       display td {class => $classCentered}, $filesystem{filesystemHist};
1914       display td {class => $classCentered},
1915         a {href =>
1916           "plot.cgi?type=filesystem&system=$system{name}"
1917         . "&filesystem=$filesystem{filesystem}"
1918         . "&scaling=Day&points=7"
1919         }, img {
1920            src    => "plotfs.cgi?system=$system{name}&"
1921                    . "filesystem=$filesystem{filesystem}"
1922                    . '&tiny=1',
1923            border => 0,
1924         };
1925     display end_Tr;
1926   } # for
1927
1928   display end_table;
1929
1930   return;
1931 } # displaySystem
1932
1933 sub displayTask (;$) {
1934   my ($task) = @_;
1935
1936   display start_table {cellspacing => 1, width => '98%'};
1937
1938   display start_Tr;
1939     display th {class => 'labelCentered'}, 'Actions';
1940     display th {class => 'labelCentered'}, 'Name';
1941     display th {class => 'labelCentered'}, 'System';
1942     display th {class => 'labelCentered'}, 'Description';
1943     display th {class => 'labelCentered'}, 'Command';
1944     display th {class => 'labelCentered'}, 'Restartable';
1945     display th {class => 'labelCentered'}, 'Category';
1946   display end_Tr;
1947
1948   for ($clearadm->FindTask ($task)) {
1949     my %task = %{$_};
1950
1951     $task{system} = 'All Systems'
1952       unless $task{system};
1953
1954     display start_Tr;
1955       my $areYouSure = "Are you sure you want to delete the $task{name} task?";
1956
1957       my $actions = start_form {
1958         method => 'post',
1959         action => 'processtask.cgi',
1960       };
1961
1962       $actions .= input {
1963         name   => 'name',
1964         type   => 'hidden',
1965         value  => $task{name},
1966       };
1967
1968       if (InArray $task{name}, @PREDEFINED_TASKS) {
1969         $actions .= input {
1970           name     => 'delete',
1971           disabled => 'true',
1972           type     => 'image',
1973           src      => 'delete.png',
1974           alt      => 'Delete',
1975           value    => 'Delete',
1976           title    => 'Cannot delete predefined task',
1977         };
1978         $actions .= input {
1979           name     => 'edit',
1980           disabled => 'true',
1981           type     => 'image',
1982           src      => 'edit.png',
1983           alt      => 'Edit',
1984           value    => 'Edit',
1985           title    => 'Cannot edit predefined task',
1986         };
1987       } else {
1988         $actions .= input {
1989           name    => 'delete',
1990           type    => 'image',
1991           src     => 'delete.png',
1992           alt     => 'Delete',
1993           value   => 'Delete',
1994           title   => 'Delete',
1995           onclick => "return AreYouSure ('$areYouSure');",
1996         };
1997         $actions .= input {
1998           name    => 'edit',
1999           type    => 'image',
2000           src     => 'edit.png',
2001           alt     => 'Edit',
2002           value   => 'Edit',
2003           title   => 'Edit',
2004         };
2005       } # if
2006
2007       display end_form;
2008
2009       display td {class => 'dataCentered'}, $actions;
2010       display td {class => 'data'},         $task{name};
2011       display td {class => 'data'},         $task{system};
2012       display td {class => 'data'},         $task{description};
2013       display td {class => 'data'},         $task{command};
2014       display td {class => 'dataCentered'}, $task{restartable};
2015       display td {class => 'data'},
2016         (InArray $task{name}, @PREDEFINED_TASKS) ? 'Predefined' : 'User Defined';
2017     display end_Tr;
2018   } # for
2019
2020   display end_table;
2021
2022   display p {class => 'center'}, a {
2023     href => 'processtask.cgi?action=Add',
2024   }, 'New task', img {
2025     src    => 'add.png',
2026     border => 0,
2027   };
2028
2029   return;
2030 } # DisplayAlerts
2031
2032 sub editAlert (;$) {
2033   my ($alert) = @_;
2034
2035   display start_form (
2036     -method   => 'post',
2037     -action   => 'processalert.cgi',
2038     -onsubmit => 'return validateAlert (this);',
2039   );
2040
2041   my %alert;
2042
2043   if ($alert) {
2044     %alert = $clearadm->GetAlert ($alert);
2045
2046     return
2047       unless %alert;
2048
2049     display input {
2050       name  => 'oldname',
2051       type  => 'hidden',
2052       value => $alert,
2053     };
2054   } else {
2055     $alert= '';
2056   } # if
2057
2058   display input {
2059     name  => 'action',
2060     type  => 'hidden',
2061     value => 'Post',
2062   };
2063
2064   display start_table {cellspacing => 1};
2065
2066   display start_Tr;
2067     display th {class => 'labelCentered'}, 'Name';
2068     display th {class => 'labelCentered'}, 'Type';
2069     display th {class => 'labelCentered'}, 'Who';
2070   display end_Tr;
2071
2072   display start_Tr;
2073     display td {
2074       class => 'data',
2075     }, input {
2076       class     => 'inputfield',
2077       maxlength => 255,
2078       name      => 'name',
2079       size      => 20,
2080       type      => 'text',
2081       value     => $alert ? $alert{name} : '',
2082     };
2083     display td {
2084       class => 'dataCentered',
2085     }, popup_menu {
2086       name    => 'type',
2087       class   => 'dropdown',
2088       values  => [ 'email', 'page', 'im' ],
2089       default => $alert ? $alert{type} : 'email',
2090     };
2091     display td {
2092       class => 'data',
2093     }, input {
2094       class     => 'inputfield',
2095       maxlength => 255,
2096       name      => 'who',
2097       size      => 20,
2098       type      => 'text',
2099       value     => $alert ? $alert{who} : '',
2100     };
2101   display end_Tr;
2102   display end_table;
2103
2104   display '<center>';
2105   display p submit ({value => $alert ? 'Update' : 'Add'}),  reset;
2106   display '</center>';
2107
2108   display end_form;
2109
2110   return;
2111 } # editAlert
2112
2113 sub editFilesystem ($$) {
2114   my ($system, $filesystem) = @_;
2115
2116   display start_form (
2117     -method => 'post',
2118     -action => 'processfilesystem.cgi',
2119   );
2120
2121   display start_table {width => '800px', cellspacing => 1};
2122
2123   display start_Tr;
2124     display th {class => 'labelCentered'}, 'Filesystem';
2125     display th {class => 'labelCentered'}, 'Type';
2126     display th {class => 'labelCentered'}, 'Mount';
2127     display th {class => 'labelCentered'}, 'Size';
2128     display th {class => 'labelCentered'}, 'Used';
2129     display th {class => 'labelCentered'}, 'Free';
2130     display th {class => 'labelCentered'}, 'Used %';
2131     display th {class => 'labelCentered'}, 'History';
2132     display th {class => 'labelCentered'}, 'Threshold';
2133   display end_Tr;
2134
2135   my %filesystem = $clearadm->GetFilesystem ($system, $filesystem);
2136   my %fs         = $clearadm->GetLatestFS   ($system, $filesystem);
2137
2138   display input {
2139     name  => 'action',
2140     type  => 'hidden',
2141     value => 'Post',
2142   };
2143   display input {
2144     name  => 'system',
2145     type  => 'hidden',
2146     value => $filesystem{system},
2147   };
2148   display input {
2149     name  => 'filesystem',
2150     type  => 'hidden',
2151     value => $filesystem{filesystem},
2152   } ;
2153
2154   my $size = autoScale $fs{size};
2155   my $used = autoScale $fs{used};
2156   my $free = autoScale $fs{free};
2157
2158   display start_Tr;
2159     display td {class => 'data'},         $filesystem{filesystem};
2160     display td {class => 'dataCentered'}, $filesystem{fstype};
2161     display td {class => 'data'},         $filesystem{mount};
2162     display td {class => 'dataRight'},    $size;
2163     display td {class => 'dataRight'},    $used;
2164     display td {class => 'dataRight'},    $free;
2165     # TODO: Note that this percentages does not agree with df output. I'm not
2166     # sure why.
2167     display td {class => 'dataCentered'},
2168       sprintf ('%.0f%%', (($fs{reserve} + $fs{used}) / $fs{size} * 100));
2169
2170     my $historyDropdown = popup_menu {
2171       name    => 'filesystemHist',
2172       class   => 'dropdown',
2173       values  => [
2174         '1 month',
2175         '2 months',
2176         '3 months',
2177         '4 months',
2178         '5 months',
2179         '6 months',
2180         '7 months',
2181         '8 months',
2182         '9 months',
2183         '10 months',
2184         '11 months',
2185         '1 year',
2186       ],
2187       default => $system ? $filesystem{filesystemHist} : '6 months',
2188     };
2189
2190     display td {
2191       class => 'dataRight',
2192     }, $historyDropdown;
2193
2194     my $thresholdDropdown = popup_menu {
2195       name    => 'threshold',
2196       class   => 'dropdown',
2197       values  => [1 .. 100],
2198       default => $filesystem{threshold},
2199     };
2200     display td {class => 'dataCentered'}, $thresholdDropdown . '%';
2201   display end_Tr;
2202
2203   display end_table;
2204
2205   display '<center>';
2206   display p submit ({value => 'Update'}),  reset;
2207   display '</center>';
2208
2209   display end_form;
2210
2211   return;
2212 } # editFilesytem
2213
2214 sub editNotification (;$) {
2215   my ($notification) = @_;
2216
2217   display start_form (
2218     -method   => 'post',
2219     -action   => 'processnotification.cgi',
2220     -onsubmit => 'return validateNotification (this);',
2221   );
2222
2223   my %notification;
2224
2225   if ($notification) {
2226     %notification = $clearadm->GetNotification ($notification);
2227
2228     return
2229       unless %notification;
2230
2231     display input {
2232       name  => 'oldname',
2233       type  => 'hidden',
2234       value => $notification,
2235     };
2236   } else {
2237     $notification = '';
2238   } # if
2239
2240   display input {
2241     name  => 'action',
2242     type  => 'hidden',
2243     value => 'Post',
2244   };
2245
2246   display start_table {cellspacing => 1};
2247
2248   display start_Tr;
2249     display th {class => 'labelCentered'}, 'Name';
2250     display th {class => 'labelCentered'}, 'Alert';
2251     display th {class => 'labelCentered'}, 'Condition';
2252     display th {class => 'labelCentered'}, 'Not More Than';
2253   display end_Tr;
2254
2255   display start_Tr;
2256     display td {
2257       class => 'data',
2258     }, input {
2259       class     => 'inputfield',
2260       maxlength => 255,
2261       name      => 'name',
2262       size      => 20,
2263       type      => 'text',
2264       value     => $notification ? $notification{name} : '',
2265     };
2266
2267     display td {
2268       class => 'dataCentered',
2269     }, makeAlertDropdown undef, $notification{alert}
2270        ? $notification{alert}
2271        : 'Email admin';
2272
2273     display td {
2274       class => 'data',
2275     }, input {
2276       class     => 'inputfield',
2277       maxlength => 255,
2278       name      => 'cond',
2279       size      => 20,
2280       type      => 'text',
2281       value     => $notification ? $notification{cond} : '',
2282     };
2283     display td {
2284       class => 'dataCentered',
2285     }, makeNoMoreThanDropdown undef, $notification{nomorethan};
2286
2287   display end_Tr;
2288   display end_table;
2289
2290   display '<center>';
2291   display p submit ({value => $notification ? 'Update' : 'Add'}),  reset;
2292   display '</center>';
2293
2294   display end_form;
2295
2296   return;
2297 } # editNotification
2298
2299 sub editSchedule (;$) {
2300   my ($schedule) = @_;
2301
2302   display start_form (
2303     -method   => 'post',
2304     -action   => 'processschedule.cgi',
2305     -onsubmit => 'return validateSchedule (this);',
2306   );
2307
2308   my %schedule;
2309
2310   if ($schedule) {
2311     %schedule = $clearadm->GetSchedule ($schedule);
2312
2313     return
2314       unless %schedule;
2315
2316     display input {
2317       name  => 'oldname',
2318       type  => 'hidden',
2319       value => $schedule,
2320     };
2321   } else {
2322     $schedule = '';
2323   } # if
2324
2325   display input {
2326     name  => 'action',
2327     type  => 'hidden',
2328     value => 'Post',
2329   };
2330
2331   display start_table {cellspacing => 1};
2332
2333   display start_Tr;
2334     display th {class => 'labelCentered'}, 'Active';
2335     display th {class => 'labelCentered'}, 'Name';
2336     display th {class => 'labelCentered'}, 'Task';
2337     display th {class => 'labelCentered'}, 'Notification';
2338     display th {class => 'labelCentered'}, 'Frequency';
2339   display end_Tr;
2340
2341   display start_Tr;
2342     display td {
2343       class => 'dataCentered',
2344     }, checkbox {
2345       name    => 'active',
2346       value   => 'true',
2347       checked => $schedule{active} eq 'false' ? 0 : 1,
2348       label   => '',
2349     };
2350     display td {
2351       class => 'data',
2352     }, input {
2353       class     => 'inputfield',
2354       maxlength => 255,
2355       name      => 'name',
2356       size      => 20,
2357       type      => 'text',
2358       value     => $schedule ? $schedule{name} : '',
2359     };
2360     display td {
2361       class => 'dataCentered',
2362     }, makeTaskDropdown undef, $schedule{task};
2363     display td {
2364       class => 'dataCentered',
2365     }, makeNotificationDropdown undef, $schedule{notification};
2366
2367     my $nbr        = 5;
2368     my $multiplier = 'minutes';
2369
2370     if ($schedule{frequency} =~ /(\d+)\s(\S+)/ ) {
2371       $nbr        = $1;
2372       $multiplier = $2;
2373
2374       $multiplier .= 's' if $nbr == 1;
2375     } # if
2376
2377     display td {
2378       class => 'data',
2379     }, input {
2380       class     => 'inputfieldRight',
2381       maxlength => 3,
2382       name      => 'nbr',
2383       size      => 1,
2384       type      => 'text',
2385       value     => $nbr,
2386     },
2387       ' ',
2388       makeMultiplierDropdown undef, $multiplier;
2389
2390   display end_Tr;
2391   display end_table;
2392
2393   display '<center>';
2394   display p submit ({value => $schedule ? 'Update' : 'Add'}),  reset;
2395   display '</center>';
2396
2397   display end_form;
2398
2399   return;
2400 } # editSchedule
2401
2402 sub editSystem (;$) {
2403   my ($system) = @_;
2404
2405   display start_form (
2406     -method   => 'post',
2407     -action   => 'processsystem.cgi',
2408     -onsubmit => 'return validateSystem (this);',
2409   );
2410
2411   my %system;
2412
2413   if ($system) {
2414     %system = $clearadm->GetSystem ($system);
2415
2416     return
2417       unless %system;
2418
2419     display input {
2420       name  => 'name',
2421       type  => 'hidden',
2422       value => $system,
2423     };
2424   } else {
2425     $system = '';
2426   } # if
2427
2428   display input {
2429     name  => 'action',
2430     type  => 'hidden',
2431     value => 'Post',
2432   };
2433
2434   display start_table {cellspacing => 1};
2435
2436   display start_Tr;
2437     display th {class => 'label'}, checkbox ({
2438       name    => 'active',
2439       value   => 'true',
2440       checked => $system{active} eq 'false' ? 0 : 1,
2441       label   => '',
2442     }) . ' Name: ';
2443
2444     if ($system) {
2445       display td {class => 'data'},  $system{name};
2446     } else {
2447       display td {
2448         class => 'data',
2449       }, input {
2450         class     => 'inputfield',
2451         maxlength => 255,
2452         name      => 'name',
2453         size      => 20,
2454         type      => 'text',
2455       };
2456     } # if
2457
2458     display th {class => 'label'}, 'Alias:';
2459     display td {
2460       class => 'data',
2461     }, input {
2462       class     => 'inputfield',
2463       maxlength => 255,
2464       name      => 'alias',
2465       size      => 20,
2466       type      => 'text',
2467       value     => $system ? $system{alias} : '',
2468     };
2469
2470     display th {class => 'label'}, 'Port:';
2471     display td {
2472       class => 'dataRight',
2473     }, input {
2474       class     => 'inputfieldRight',
2475       maxlength => 6,
2476       name      => 'port',
2477       size      => 4,
2478       type      => 'text',
2479       value     => $system
2480                  ? $system{port}
2481                  : $Clearadm::CLEAROPTS{CLEARADM_PORT},
2482     };
2483
2484     my $systemTypeDropdown = popup_menu {
2485       name    => 'type',
2486       class   => 'dropdown',
2487       values  => ['Unix', 'Linux', 'Windows'],
2488       default => $system ? $system{type} : 'Linux',
2489     };
2490
2491     display th {class => 'label'}, 'Type:';
2492     display td {
2493       class   => 'dataRight',
2494     },  $systemTypeDropdown;
2495   display end_Tr;
2496
2497   display start_Tr;
2498     display th {class => 'label'}, 'Admin:';
2499     display td {
2500       class => 'data',
2501     }, input {
2502       class     => 'inputfield',
2503       maxlength => 255,
2504       name      => 'admin',
2505       size      => 20,
2506       type      => 'text',
2507       value     => $system ? $system{admin} : '',
2508     };
2509     display th {class => 'label'}, 'Admin Email:';
2510     display td {
2511       class => 'data',
2512     }, input {
2513       class     => 'inputfield',
2514       maxlength => 255,
2515       name      => 'email',
2516       size      => 20,
2517       type      => 'text',
2518       value     => $system ? $system{email} : '',
2519     };
2520
2521     display th {class => 'label'}, 'Threshold:';
2522     display td {
2523       class => 'dataRight',
2524     }, input {
2525       class     => 'inputfieldRight',
2526       maxlength => 5,
2527       name      => 'loadavgThreshold',
2528       size      => 3,
2529       type      => 'text',
2530       value     => $system
2531                  ? $system{loadavgThreshold}
2532                  : $Clearadm::CLEAROPTS{CLEARADM_LOADAVG_THRESHOLD},
2533     };
2534
2535     my $historyDropdown = popup_menu {
2536       name    => 'loadavgHist',
2537       class   => 'dropdown',
2538       values  => [
2539         '1 month',
2540         '2 months',
2541         '3 months',
2542         '4 months',
2543         '5 months',
2544         '6 months',
2545         '7 months',
2546         '8 months',
2547         '9 months',
2548         '10 months',
2549         '11 months',
2550         '1 year',
2551       ],
2552       default => $system ? $system{loadavgHist} : '6 months',
2553     };
2554
2555     display th {class => 'label'}, 'History:';
2556     display td {
2557       class => 'dataRight',
2558     }, $historyDropdown;
2559
2560   my $description = $system ? $system{description} : '';
2561      $description =~ s/\r\n/<br>/g;
2562
2563   display start_Tr;
2564     display th {class => 'label'}, 'Description:';
2565     display td {
2566       class   => 'data',
2567       colspan => 7,
2568     }, textarea {
2569       class   => 'inputfield',
2570       cols    => 103,
2571       name    => 'description',
2572       rows    => 3,
2573       value   => $description,
2574     };
2575   display end_Tr;
2576   display end_table;
2577
2578   display '<center>';
2579   display p submit ({value => $system ? 'Update' : 'Add'}),  reset;
2580   display '</center>';
2581
2582   display end_form;
2583
2584   return;
2585 } # editSystem
2586
2587 sub editTask (;$) {
2588   my ($task) = @_;
2589
2590   display start_form (
2591     -method   => 'post',
2592     -action   => 'processtask.cgi',
2593     -onsubmit => 'return validateTask (this);',
2594   );
2595
2596   my %task;
2597
2598   if ($task) {
2599     %task = $clearadm->GetTask ($task);
2600
2601     return
2602       unless %task;
2603
2604     display input {
2605       name  => 'oldname',
2606       type  => 'hidden',
2607       value => $task,
2608     };
2609   } else {
2610     $task = '';
2611   } # if
2612
2613   display input {
2614     name  => 'action',
2615     type  => 'hidden',
2616     value => 'Post',
2617   };
2618
2619   display start_table {cellspacing => 1};
2620
2621   display start_Tr;
2622     display th {class => 'labelCentered'}, 'Name';
2623     display th {class => 'labelCentered'}, 'System';
2624     display th {class => 'labelCentered'}, 'Description';
2625     display th {class => 'labelCentered'}, 'Command';
2626     display th {class => 'labelCentered'}, 'Restartable';
2627   display end_Tr;
2628
2629   display start_Tr;
2630     display td {
2631       class => 'data',
2632     }, input {
2633       class     => 'inputfield',
2634       maxlength => 255,
2635       name      => 'name',
2636       size      => 15,
2637       type      => 'text',
2638       value     => $task ? $task{name} : '',
2639     };
2640     my $systemDropdown = makeSystemDropdown (
2641       undef,
2642       $task{system} ? $task{system} : 'localhost',
2643       undef, (
2644         'localhost' => 'localhost',
2645       ),
2646     );
2647
2648     display td {class => 'data'}, $systemDropdown;
2649
2650     display td {
2651       class => 'data',
2652     }, input {
2653       class     => 'inputfield',
2654       maxlength => 255,
2655       name      => 'description',
2656       size      => 30,
2657       type      => 'text',
2658       value     => $task ? $task{description} : '',
2659     };
2660
2661     display td {
2662       class => 'data',
2663     }, input {
2664       class     => 'inputfield',
2665       maxlength => 255,
2666       name      => 'command',
2667       size      => 40,
2668       type      => 'text',
2669       value     => $task ? $task{command} : '',
2670     };
2671
2672     display td {
2673       class => 'dataCentered',
2674     }, makeRestartableDropdown undef, $task{restartable};
2675
2676   display end_Tr;
2677   display end_table;
2678
2679   display '<center>';
2680   display p submit ({value => $task ? 'Update' : 'Add'}),  reset;
2681   display '</center>';
2682
2683   display end_form;
2684
2685   return;
2686 } # editTask
2687
2688 sub footing () {
2689   my $clearscm = a {-href => 'http://clearscm.com'}, 'ClearSCM, Inc.';
2690
2691   # Figure out which script by using CLEARADM_BASE.
2692   my $script = basename (url {-absolute => 1});
2693      $script = 'index.cgi'
2694        if $script eq 'clearadm';
2695
2696   my $scriptFullPath = "$Clearadm::CLEAROPTS{CLEARADM_BASE}/$script";
2697
2698   my ($year, $mon, $mday, $hour, $min, $sec) =
2699     ymdhms ((stat ($scriptFullPath))[9]);
2700
2701   my $dateModified = "$mon/$mday/$year @ $hour:$min";
2702
2703   $script = a {
2704     -href => "http://clearscm.com/php/scm_man.php?file=clearadm/$script"
2705   }, $script;
2706
2707   display end_div;
2708
2709   display start_div {-class => 'copyright'};
2710     display "$script: Last modified: $dateModified";
2711     display br "Copyright &copy; $year, $clearscm - All rights reserved";
2712   display end_div;
2713
2714   print end_html;
2715
2716   return;
2717 } # footing
2718
2719 1;
2720
2721 =pod
2722
2723 =head1 CONFIGURATION AND ENVIRONMENT
2724
2725 DEBUG: If set then $debug is set to this level.
2726
2727 VERBOSE: If set then $verbose is set to this level.
2728
2729 TRACE: If set then $trace is set to this level.
2730
2731 =head1 DEPENDENCIES
2732
2733 =head2 Perl Modules
2734
2735 L<Carp>
2736
2737 L<CGI>
2738
2739 L<File::Basename|File::Basename>
2740
2741 L<FindBin>
2742
2743 L<GD>
2744
2745 =head2 ClearSCM Perl Modules
2746
2747 =begin man
2748
2749  Clearadm
2750  DateUtils
2751  Display
2752  Utils
2753
2754 =end man
2755
2756 =begin html
2757
2758 <blockquote>
2759 <a href="http://clearscm.com/php/scm_man.php?file=lib/Clearadm.pm">Clearadm</a><br>
2760 <a href="http://clearscm.com/php/scm_man.php?file=lib/DateUtils.pm">DateUtils</a><br>
2761 <a href="http://clearscm.com/php/scm_man.php?file=lib/Display.pm">Display</a><br>
2762 <a href="http://clearscm.com/php/scm_man.php?file=lib/Utils.pm">Utils</a><br>
2763 </blockquote>
2764
2765 =end html
2766
2767 =head1 BUGS AND LIMITATIONS
2768
2769 There are no known bugs in this module.
2770
2771 Please report problems to Andrew DeFaria <Andrew@ClearSCM.com>.
2772
2773 =head1 LICENSE AND COPYRIGHT
2774
2775 Copyright (c) 2010, ClearSCM, Inc. All rights reserved.
2776
2777 =cut