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