Annotation of loncom/loncron, revision 1.82

1.1       albertel    1: #!/usr/bin/perl
                      2: 
1.47      albertel    3: # Housekeeping program, started by cron, loncontrol and loncron.pl
                      4: #
1.82    ! raeburn     5: # $Id: loncron,v 1.81 2009/06/11 00:15:27 raeburn Exp $
1.47      albertel    6: #
                      7: # Copyright Michigan State University Board of Trustees
                      8: #
                      9: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
                     10: #
                     11: # LON-CAPA is free software; you can redistribute it and/or modify
                     12: # it under the terms of the GNU General Public License as published by
                     13: # the Free Software Foundation; either version 2 of the License, or
                     14: # (at your option) any later version.
                     15: #
                     16: # LON-CAPA is distributed in the hope that it will be useful,
                     17: # but WITHOUT ANY WARRANTY; without even the implied warranty of
                     18: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     19: # GNU General Public License for more details.
                     20: #
                     21: # You should have received a copy of the GNU General Public License
                     22: # along with LON-CAPA; if not, write to the Free Software
                     23: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                     24: #
                     25: # /home/httpd/html/adm/gpl.txt
                     26: #
                     27: # http://www.lon-capa.org/
1.1       albertel   28: #
1.24      www        29: 
                     30: $|=1;
1.48      albertel   31: use strict;
1.1       albertel   32: 
1.26      harris41   33: use lib '/home/httpd/lib/perl/';
                     34: use LONCAPA::Configuration;
1.72      albertel   35: use Apache::lonnet;
1.79      raeburn    36: use Apache::loncommon;
1.26      harris41   37: 
1.1       albertel   38: use IO::File;
                     39: use IO::Socket;
1.48      albertel   40: use HTML::Entities;
1.49      albertel   41: use Getopt::Long;
1.46      albertel   42: #globals
                     43: use vars qw (%perlvar %simplestatus $errors $warnings $notices $totalcount);
                     44: 
                     45: my $statusdir="/home/httpd/html/lon-status";
                     46: 
1.1       albertel   47: 
                     48: # --------------------------------------------------------- Output error status
                     49: 
1.46      albertel   50: sub log {
                     51:     my $fh=shift;
                     52:     if ($fh) {	print $fh @_  }
                     53: }
                     54: 
1.1       albertel   55: sub errout {
                     56:    my $fh=shift;
1.46      albertel   57:    &log($fh,(<<ENDERROUT));
1.48      albertel   58:      <table border="2" bgcolor="#CCCCCC">
1.1       albertel   59:      <tr><td>Notices</td><td>$notices</td></tr>
                     60:      <tr><td>Warnings</td><td>$warnings</td></tr>
                     61:      <tr><td>Errors</td><td>$errors</td></tr>
1.48      albertel   62:      </table><p><a href="#top">Top</a></p>
1.1       albertel   63: ENDERROUT
                     64: }
                     65: 
1.73      albertel   66: sub rotate_logfile {
                     67:     my ($file,$fh,$description) = @_;
                     68:     my $size=(stat($file))[7];
                     69:     if ($size>40000) {
                     70: 	&log($fh,"<p>Rotating $description ...</p>");
                     71: 	rename("$file.2","$file.3");
                     72: 	rename("$file.1","$file.2");
                     73: 	rename("$file","$file.1");
                     74:     } 
                     75: }
                     76: 
1.42      albertel   77: sub start_daemon {
1.50      albertel   78:     my ($fh,$daemon,$pidfile,$args) = @_;
1.44      albertel   79:     my $progname=$daemon;
1.71      albertel   80:     if ($daemon eq 'lonc') {
1.44      albertel   81: 	$progname='loncnew'; 
                     82:     }
1.51      albertel   83:     my $error_fname="$perlvar{'lonDaemons'}/logs/${daemon}_errors";
1.73      albertel   84:     &rotate_logfile($error_fname,$fh,'error logs');
1.74      albertel   85:     if ($daemon eq 'lonc') {
                     86: 	&clean_sockets($fh);
                     87:     }
1.51      albertel   88:     system("$perlvar{'lonDaemons'}/$progname 2>$perlvar{'lonDaemons'}/logs/${daemon}_errors");
1.60      albertel   89:     sleep 1;
1.42      albertel   90:     if (-e $pidfile) {
1.48      albertel   91: 	&log($fh,"<p>Seems like it started ...</p>");
1.42      albertel   92: 	my $lfh=IO::File->new("$pidfile");
                     93: 	my $daemonpid=<$lfh>;
                     94: 	chomp($daemonpid);
1.62      albertel   95: 	if ($daemonpid =~ /^\d+$/ && kill 0 => $daemonpid) {
1.42      albertel   96: 	    return 1;
                     97: 	} else {
                     98: 	    return 0;
                     99: 	}
                    100:     }
1.48      albertel  101:     &log($fh,"<p>Seems like that did not work!</p>");
1.42      albertel  102:     $errors++;
                    103:     return 0;
                    104: }
                    105: 
                    106: sub checkon_daemon {
1.59      albertel  107:     my ($fh,$daemon,$maxsize,$send,$args)=@_;
1.42      albertel  108: 
1.63      albertel  109:     my $result;
1.48      albertel  110:     &log($fh,'<hr /><a name="'.$daemon.'" /><h2>'.$daemon.'</h2><h3>Log</h3><p style="white-space: pre;"><tt>');
1.57      albertel  111:     printf("%-15s ",$daemon);
1.42      albertel  112:     if (-e "$perlvar{'lonDaemons'}/logs/$daemon.log"){
                    113: 	open (DFH,"tail -n25 $perlvar{'lonDaemons'}/logs/$daemon.log|");
1.46      albertel  114: 	while (my $line=<DFH>) { 
                    115: 	    &log($fh,"$line");
1.42      albertel  116: 	    if ($line=~/INFO/) { $notices++; }
                    117: 	    if ($line=~/WARNING/) { $notices++; }
                    118: 	    if ($line=~/CRITICAL/) { $warnings++; }
                    119: 	};
                    120: 	close (DFH);
                    121:     }
1.48      albertel  122:     &log($fh,"</tt></p>");
1.42      albertel  123:     
                    124:     my $pidfile="$perlvar{'lonDaemons'}/logs/$daemon.pid";
                    125:     
                    126:     my $restartflag=1;
1.46      albertel  127:     my $daemonpid;
1.42      albertel  128:     if (-e $pidfile) {
                    129: 	my $lfh=IO::File->new("$pidfile");
1.46      albertel  130: 	$daemonpid=<$lfh>;
1.42      albertel  131: 	chomp($daemonpid);
1.62      albertel  132: 	if ($daemonpid =~ /^\d+$/ && kill 0 => $daemonpid) {
1.46      albertel  133: 	    &log($fh,"<h3>$daemon at pid $daemonpid responding");
1.59      albertel  134: 	    if ($send) { &log($fh,", sending $send"); }
1.46      albertel  135: 	    &log($fh,"</h3>");
1.59      albertel  136: 	    if ($send eq 'USR1') { kill USR1 => $daemonpid; }
                    137: 	    if ($send eq 'USR2') { kill USR2 => $daemonpid; }
1.42      albertel  138: 	    $restartflag=0;
1.59      albertel  139: 	    if ($send eq 'USR2') {
1.63      albertel  140: 		$result = 'reloaded';
1.59      albertel  141: 		print "reloaded\n";
                    142: 	    } else {
1.63      albertel  143: 		$result = 'running';
1.59      albertel  144: 		print "running\n";
                    145: 	    }
1.42      albertel  146: 	} else {
                    147: 	    $errors++;
1.46      albertel  148: 	    &log($fh,"<h3>$daemon at pid $daemonpid not responding</h3>");
1.42      albertel  149: 	    $restartflag=1;
1.46      albertel  150: 	    &log($fh,"<h3>Decided to clean up stale .pid file and restart $daemon</h3>");
1.42      albertel  151: 	}
                    152:     }
                    153:     if ($restartflag==1) {
                    154: 	$simplestatus{$daemon}='off';
                    155: 	$errors++;
1.57      albertel  156: 	my $kadaemon=$daemon;
                    157: 	if ($kadaemon eq 'lonmemcached') { $kadaemon='memcached'; }
1.46      albertel  158: 	&log($fh,'<br><font color="red">Killall '.$daemon.': '.
1.57      albertel  159: 	    `killall $kadaemon 2>&1`.' - ');
1.60      albertel  160: 	sleep 1;
1.46      albertel  161: 	&log($fh,unlink($pidfile).' - '.
1.57      albertel  162: 	    `killall -9 $kadaemon 2>&1`.
1.46      albertel  163: 	    '</font><br>');
                    164: 	&log($fh,"<h3>$daemon not running, trying to start</h3>");
1.42      albertel  165: 	
1.50      albertel  166: 	if (&start_daemon($fh,$daemon,$pidfile,$args)) {
1.46      albertel  167: 	    &log($fh,"<h3>$daemon at pid $daemonpid responding</h3>");
1.42      albertel  168: 	    $simplestatus{$daemon}='restarted';
1.63      albertel  169: 	    $result = 'started';
1.42      albertel  170: 	    print "started\n";
                    171: 	} else {
                    172: 	    $errors++;
1.46      albertel  173: 	    &log($fh,"<h3>$daemon at pid $daemonpid not responding</h3>");
1.48      albertel  174: 	    &log($fh,"<p>Give it one more try ...</p>");
1.42      albertel  175: 	    print " ";
1.50      albertel  176: 	    if (&start_daemon($fh,$daemon,$pidfile,$args)) {
1.46      albertel  177: 		&log($fh,"<h3>$daemon at pid $daemonpid responding</h3>");
1.42      albertel  178: 		$simplestatus{$daemon}='restarted';
1.63      albertel  179: 		$result = 'started';
1.42      albertel  180: 		print "started\n";
                    181: 	    } else {
1.63      albertel  182: 		$result = 'failed';
1.42      albertel  183: 		print " failed\n";
                    184: 		$simplestatus{$daemon}='failed';
                    185: 		$errors++; $errors++;
1.46      albertel  186: 		&log($fh,"<h3>$daemon at pid $daemonpid not responding</h3>");
1.48      albertel  187: 		&log($fh,"<p>Unable to start $daemon</p>");
1.42      albertel  188: 	    }
                    189: 	}
                    190: 
                    191: 	if (-e "$perlvar{'lonDaemons'}/logs/$daemon.log"){
1.46      albertel  192: 	    &log($fh,"<p><pre>");
1.42      albertel  193: 	    open (DFH,"tail -n100 $perlvar{'lonDaemons'}/logs/$daemon.log|");
1.46      albertel  194: 	    while (my $line=<DFH>) { 
                    195: 		&log($fh,"$line");
1.42      albertel  196: 		if ($line=~/WARNING/) { $notices++; }
                    197: 		if ($line=~/CRITICAL/) { $notices++; }
                    198: 	    };
                    199: 	    close (DFH);
1.48      albertel  200: 	    &log($fh,"</pre></p>");
1.42      albertel  201: 	}
                    202:     }
                    203:     
1.46      albertel  204:     my $fname="$perlvar{'lonDaemons'}/logs/$daemon.log";
1.73      albertel  205:     &rotate_logfile($fname,$fh,'logs');
1.42      albertel  206: 
                    207:     &errout($fh);
1.63      albertel  208:     return $result;
1.42      albertel  209: }
1.1       albertel  210: 
1.46      albertel  211: # --------------------------------------------------------------------- Machine
                    212: sub log_machine_info {
                    213:     my ($fh)=@_;
1.48      albertel  214:     &log($fh,'<hr /><a name="machine" /><h2>Machine Information</h2>');
1.46      albertel  215:     &log($fh,"<h3>loadavg</h3>");
                    216: 	
                    217:     open (LOADAVGH,"/proc/loadavg");
                    218:     my $loadavg=<LOADAVGH>;
                    219:     close (LOADAVGH);
                    220:     
                    221:     &log($fh,"<tt>$loadavg</tt>");
                    222:     
                    223:     my @parts=split(/\s+/,$loadavg);
                    224:     if ($parts[1]>4.0) {
                    225: 	$errors++;
                    226:     } elsif ($parts[1]>2.0) {
                    227: 	$warnings++;
                    228:     } elsif ($parts[1]>1.0) {
                    229: 	$notices++;
                    230:     }
1.13      harris41  231: 
1.46      albertel  232:     &log($fh,"<h3>df</h3>");
                    233:     &log($fh,"<pre>");
1.14      harris41  234: 
1.46      albertel  235:     open (DFH,"df|");
                    236:     while (my $line=<DFH>) { 
1.48      albertel  237: 	&log($fh,&encode_entities($line,'<>&"')); 
1.46      albertel  238: 	@parts=split(/\s+/,$line);
                    239: 	my $usage=$parts[4];
                    240: 	$usage=~s/\W//g;
                    241: 	if ($usage>90) { 
                    242: 	    $warnings++;
                    243: 	    $notices++; 
                    244: 	} elsif ($usage>80) {
                    245: 	    $warnings++;
                    246: 	} elsif ($usage>60) {
                    247: 	    $notices++;
1.31      albertel  248: 	}
1.46      albertel  249: 	if ($usage>95) { $warnings++; $warnings++; $simplestatus{'diskfull'}++; }
1.1       albertel  250:     }
1.46      albertel  251:     close (DFH);
                    252:     &log($fh,"</pre>");
1.1       albertel  253: 
                    254: 
1.46      albertel  255:     &log($fh,"<h3>ps</h3>");
                    256:     &log($fh,"<pre>");
                    257:     my $psproc=0;
1.1       albertel  258: 
1.53      albertel  259:     open (PSH,"ps aux --cols 140 |");
1.46      albertel  260:     while (my $line=<PSH>) { 
1.48      albertel  261: 	&log($fh,&encode_entities($line,'<>&"')); 
1.46      albertel  262: 	$psproc++;
                    263:     }
                    264:     close (PSH);
                    265:     &log($fh,"</pre>");
1.1       albertel  266: 
1.46      albertel  267:     if ($psproc>200) { $notices++; }
                    268:     if ($psproc>250) { $notices++; }
1.1       albertel  269: 
1.61      albertel  270:     &log($fh,"<h3>distprobe</h3>");
                    271:     &log($fh,"<pre>");
                    272:     open(DSH,"$perlvar{'lonDaemons'}/distprobe |");
                    273:     while (my $line=<DSH>) { 
                    274: 	&log($fh,&encode_entities($line,'<>&"')); 
                    275: 	$psproc++;
                    276:     }
                    277:     close(DSH);
                    278:     &log($fh,"</pre>");
                    279: 
1.46      albertel  280:     &errout($fh);
                    281: }
1.1       albertel  282: 
1.46      albertel  283: sub start_logging {
1.43      albertel  284:     my $fh=IO::File->new(">$statusdir/newstatus.html");
                    285:     my %simplestatus=();
1.46      albertel  286:     my $now=time;
                    287:     my $date=localtime($now);
1.43      albertel  288:     
1.46      albertel  289: 
                    290:     &log($fh,(<<ENDHEADERS));
1.1       albertel  291: <html>
                    292: <head>
                    293: <title>LON Status Report $perlvar{'lonHostID'}</title>
                    294: </head>
1.3       www       295: <body bgcolor="#AAAAAA">
1.48      albertel  296: <a name="top" />
1.1       albertel  297: <h1>LON Status Report $perlvar{'lonHostID'}</h1>
                    298: <h2>$date ($now)</h2>
                    299: <ol>
1.48      albertel  300: <li><a href="#configuration">Configuration</a></li>
                    301: <li><a href="#machine">Machine Information</a></li>
                    302: <li><a href="#tmp">Temporary Files</a></li>
                    303: <li><a href="#tokens">Session Tokens</a></li>
                    304: <li><a href="#httpd">httpd</a></li>
                    305: <li><a href="#lonsql">lonsql</a></li>
                    306: <li><a href="#lond">lond</a></li>
                    307: <li><a href="#lonc">lonc</a></li>
                    308: <li><a href="#lonnet">lonnet</a></li>
                    309: <li><a href="#connections">Connections</a></li>
                    310: <li><a href="#delayed">Delayed Messages</a></li>
                    311: <li><a href="#errcount">Error Count</a></li>
1.1       albertel  312: </ol>
1.48      albertel  313: <hr />
                    314: <a name="configuration" />
1.1       albertel  315: <h2>Configuration</h2>
                    316: <h3>PerlVars</h3>
1.48      albertel  317: <table border="2">
1.1       albertel  318: ENDHEADERS
                    319: 
1.46      albertel  320:     foreach my $varname (sort(keys(%perlvar))) {
1.48      albertel  321: 	&log($fh,"<tr><td>$varname</td><td>".
                    322: 	     &encode_entities($perlvar{$varname},'<>&"')."</td></tr>\n");
1.43      albertel  323:     }
1.48      albertel  324:     &log($fh,"</table><h3>Hosts</h3><table border='2'>");
1.72      albertel  325:     my %hostname = &Apache::lonnet::all_hostnames();
                    326:     foreach my $id (sort(keys(%hostname))) {
                    327: 	my $role = (&Apache::lonnet::is_library($id) ? 'library'
                    328: 		                                     : 'access');
1.46      albertel  329: 	&log($fh,
1.72      albertel  330: 	    "<tr><td>$id</td><td>".&Apache::lonnet::host_domain($id).
                    331: 	    "</td><td>".$role.
                    332: 	    "</td><td>".&Apache::lonnet::hostname($id)."</td></tr>\n");
                    333:     }
                    334:     &log($fh,"</table><h3>Spare Hosts</h3><ul>");
                    335:     foreach my $type (sort(keys(%Apache::lonnet::spareid))) {
                    336: 	&log($fh,"<li>$type\n<ol>");
                    337: 	foreach my $id (@{ $Apache::lonnet::spareid{$type} }) {
                    338: 	    &log($fh,"<li>$id</li>\n");
                    339: 	}
                    340: 	&log($fh,"</ol>\n</li>\n");
1.43      albertel  341:     }
1.72      albertel  342:     &log($fh,"</ul>\n");
1.46      albertel  343:     return $fh;
                    344: }
1.11      www       345: 
                    346: # --------------------------------------------------------------- clean out tmp
1.46      albertel  347: sub clean_tmp {
                    348:     my ($fh)=@_;
1.48      albertel  349:     &log($fh,'<hr /><a name="tmp" /><h2>Temporary Files</h2>');
1.82    ! raeburn   350:     my ($cleaned,$old,$removed) = (0,0,0);
        !           351:     my %errors = (
        !           352:                      dir       => [],
        !           353:                      file      => [],
        !           354:                      failopen  => [],
        !           355:                  );
        !           356:     my %error_titles = (
        !           357:                          dir       => 'failed to remove empty directory:',
        !           358:                          file      => 'failed to unlike stale file',
        !           359:                          failopen  => 'failed to open file or directory'
        !           360:                        );
        !           361:     ($cleaned,$old,$removed) = &recursive_clean_tmp('',$cleaned,$old,$removed,\%errors);
        !           362:     &log($fh,"Cleaned up: ".$cleaned." files; removed: $removed empty directories; (found: $old old checkout tokens)");
        !           363:     foreach my $key (sort(keys(%errors))) {
        !           364:         if (ref($errors{$key}) eq 'ARRAY') {
        !           365:             if (@{$errors{$key}} > 0) {
        !           366:                 &log($fh,"Error during cleanup ($error_titles{$key}):<ul><li>".
        !           367:                      join('</li><li><tt>',@{$errors{$key}}).'</tt></li></ul><br />');
        !           368:             }
        !           369:         }
        !           370:     }
        !           371: }
        !           372: 
        !           373: sub recursive_clean_tmp {
        !           374:     my ($subdir,$cleaned,$old,$removed,$errors) = @_;
        !           375:     my $base = "$perlvar{'lonDaemons'}/tmp";
        !           376:     my $path = $base;
        !           377:     next if ($subdir =~ m{\.\./});
        !           378:     next unless (ref($errors) eq 'HASH');
        !           379:     unless ($subdir eq '') {
        !           380:         $path .= '/'.$subdir;
        !           381:     }
        !           382:     if (opendir(my $dh,"$path")) {
        !           383:         while (my $file = readdir($dh)) {
        !           384:             next if ($file =~ /^\.\.?$/);
        !           385:             my $fname = "$path/$file";
        !           386:             if (-d $fname) {
        !           387:                 my $innerdir;
        !           388:                 if ($subdir eq '') {
        !           389:                     $innerdir = $file;
        !           390:                 } else {
        !           391:                     $innerdir = $subdir.'/'.$file;
        !           392:                 }
        !           393:                 ($cleaned,$old,$removed) = 
        !           394:                      &recursive_clean_tmp($innerdir,$cleaned,$old,$removed,$errors);
        !           395:                 my @doms = &Apache::lonnet::current_machine_domains();
        !           396:                 
        !           397:                 if (open(my $dirhandle,$fname)) {
        !           398:                     unless (($innerdir eq 'helprequests') ||
        !           399:                             (($innerdir =~ /^addcourse/) && ($innerdir !~ m{/\d+$}))) {
        !           400:                         my @contents = grep {!/^\.\.?$/} readdir($dirhandle);
        !           401:                                       join('&&',@contents)."\n";    
        !           402:                         if (scalar(grep {!/^\.\.?$/} readdir($dirhandle)) == 0) {
        !           403:                             closedir($dirhandle);
        !           404:                             if ($fname =~ m{^\Q$perlvar{'lonDaemons'}\E/tmp/}) {
        !           405:                                 if (rmdir($fname)) {
        !           406:                                     $removed ++;
        !           407:                                 } elsif (ref($errors->{dir}) eq 'ARRAY') {
        !           408:                                     push(@{$errors->{dir}},$fname);
        !           409:                                 }
        !           410:                             }
        !           411:                         }
        !           412:                     } else {
        !           413:                         closedir($dirhandle);
        !           414:                     }
        !           415:                 }
        !           416:             } else {
        !           417:                 my ($dev,$ino,$mode,$nlink,
        !           418:                     $uid,$gid,$rdev,$size,
        !           419:                     $atime,$mtime,$ctime,
        !           420:                     $blksize,$blocks)=stat($fname);
        !           421:                 my $now=time;
        !           422:                 my $since=$now-$mtime;
        !           423:                 if ($since>$perlvar{'lonExpire'}) {
        !           424:                     if ($subdir eq '') {
        !           425:                         my $line='';
        !           426:                         if ($fname =~ /\.db$/) {
        !           427:                             if (unlink($fname)) {
        !           428:                                 $cleaned++;
        !           429:                             } elsif (ref($errors->{file}) eq 'ARRAY') {
        !           430:                                 push(@{$errors->{file}},$fname);
        !           431:                             }
        !           432:                         } elsif (open(PROBE,$fname)) {
        !           433:                             my $line='';
        !           434:                             $line=<PROBE>;
        !           435:                             close(PROBE);
        !           436:                             if ($line=~/^CHECKOUTTOKEN\&/) {
        !           437:                                 if ($since>365*$perlvar{'lonExpire'}) {
        !           438:                                     if (unlink($fname)) {
        !           439:                                         $cleaned++; 
        !           440:                                     } elsif (ref($errors->{file}) eq 'ARRAY') {
        !           441:                                         push(@{$errors->{file}},$fname);
        !           442:                                     }
        !           443:                                 } else {
        !           444:                                     $old++;
        !           445:                                 }
        !           446:                             } else {
        !           447:                                 if (unlink($fname)) {
        !           448:                                     $cleaned++;
        !           449:                                 } elsif (ref($errors->{file}) eq 'ARRAY') {
        !           450:                                     push(@{$errors->{file}},$fname);
        !           451:                                 }
        !           452:                             }
        !           453:                         } elsif (ref($errors->{failopen}) eq 'ARRAY') {
        !           454:                             push(@{$errors->{failopen}},$fname); 
        !           455:                         }
        !           456:                     } else {
        !           457:                         if (unlink($fname)) {
        !           458:                             $cleaned++;
        !           459:                         } elsif (ref($errors->{file}) eq 'ARRAY') {
        !           460:                             push(@{$errors->{file}},$fname);
        !           461:                         }
        !           462:                     }
        !           463:                 }
        !           464:             }
        !           465:         }
        !           466:         closedir($dh);
        !           467:     } elsif (ref($errors->{failopen}) eq 'ARRAY') {
        !           468:         push(@{$errors->{failopen}},$path);
1.43      albertel  469:     }
1.82    ! raeburn   470:     return ($cleaned,$old,$removed);
1.46      albertel  471: }
1.11      www       472: 
                    473: # ------------------------------------------------------------ clean out lonIDs
1.46      albertel  474: sub clean_lonIDs {
                    475:     my ($fh)=@_;
1.48      albertel  476:     &log($fh,'<hr /><a name="tokens" /><h2>Session Tokens</h2>');
1.46      albertel  477:     my $cleaned=0;
                    478:     my $active=0;
                    479:     while (my $fname=<$perlvar{'lonIDsDir'}/*>) {
1.43      albertel  480: 	my ($dev,$ino,$mode,$nlink,
                    481: 	    $uid,$gid,$rdev,$size,
                    482: 	    $atime,$mtime,$ctime,
                    483: 	    $blksize,$blocks)=stat($fname);
1.46      albertel  484: 	my $now=time;
                    485: 	my $since=$now-$mtime;
1.43      albertel  486: 	if ($since>$perlvar{'lonExpire'}) {
                    487: 	    $cleaned++;
1.46      albertel  488: 	    &log($fh,"Unlinking $fname<br>");
1.43      albertel  489: 	    unlink("$fname");
                    490: 	} else {
                    491: 	    $active++;
                    492: 	}
1.46      albertel  493:     }
1.48      albertel  494:     &log($fh,"<p>Cleaned up ".$cleaned." stale session token(s).</p>");
1.46      albertel  495:     &log($fh,"<h3>$active open session(s)</h3>");
                    496: }
1.43      albertel  497: 
1.74      albertel  498: # ----------------------------------------------------------- clean out sockets
                    499: sub clean_sockets {
                    500:     my ($fh)=@_;
                    501:     my $cleaned=0;
                    502:     opendir(SOCKETS,$perlvar{'lonSockDir'});
                    503:     while (my $fname=readdir(SOCKETS)) {
                    504: 	next if (-d $fname 
1.80      www       505: 		 || $fname=~/(mysqlsock|maximasock|rsock|\Q$perlvar{'lonSockDir'}\E)/);
1.74      albertel  506: 	$cleaned++;
                    507: 	&log($fh,"Unlinking $fname<br />");
                    508: 	unlink("/home/httpd/sockets/$fname");
                    509:     }
                    510:     &log($fh,"<p>Cleaned up ".$cleaned." stale sockets.</p>");
                    511: }
                    512: 
1.11      www       513: 
1.1       albertel  514: # ----------------------------------------------------------------------- httpd
1.46      albertel  515: sub check_httpd_logs {
                    516:     my ($fh)=@_;
1.48      albertel  517:     &log($fh,'<hr /><a name="httpd" /><h2>httpd</h2><h3>Access Log</h3><pre>');
1.43      albertel  518:     
                    519:     open (DFH,"tail -n25 /etc/httpd/logs/access_log|");
1.48      albertel  520:     while (my $line=<DFH>) { &log($fh,&encode_entities($line,'<>&"')) };
1.43      albertel  521:     close (DFH);
1.46      albertel  522: 	
                    523:     &log($fh,"</pre><h3>Error Log</h3><pre>");
                    524: 	
1.43      albertel  525:     open (DFH,"tail -n25 /etc/httpd/logs/error_log|");
1.46      albertel  526:     while (my $line=<DFH>) { 
                    527: 	&log($fh,"$line");
1.43      albertel  528: 	if ($line=~/\[error\]/) { $notices++; } 
1.46      albertel  529:     }
1.43      albertel  530:     close (DFH);
1.46      albertel  531:     &log($fh,"</pre>");
1.43      albertel  532:     &errout($fh);
1.46      albertel  533: }
1.1       albertel  534: 
                    535: # ---------------------------------------------------------------------- lonnet
                    536: 
1.48      albertel  537: sub rotate_lonnet_logs {
1.46      albertel  538:     my ($fh)=@_;
1.48      albertel  539:     &log($fh,'<hr /><a name="lonnet" /><h2>lonnet</h2><h3>Temp Log</h3><pre>');
1.43      albertel  540:     print "checking logs\n";
                    541:     if (-e "$perlvar{'lonDaemons'}/logs/lonnet.log"){
                    542: 	open (DFH,"tail -n50 $perlvar{'lonDaemons'}/logs/lonnet.log|");
1.46      albertel  543: 	while (my $line=<DFH>) { 
1.48      albertel  544: 	    &log($fh,&encode_entities($line,'<>&"'));
1.46      albertel  545: 	}
1.43      albertel  546: 	close (DFH);
                    547:     }
1.46      albertel  548:     &log($fh,"</pre><h3>Perm Log</h3><pre>");
1.43      albertel  549:     
                    550:     if (-e "$perlvar{'lonDaemons'}/logs/lonnet.perm.log") {
                    551: 	open(DFH,"tail -n10 $perlvar{'lonDaemons'}/logs/lonnet.perm.log|");
1.46      albertel  552: 	while (my $line=<DFH>) { 
1.48      albertel  553: 	    &log($fh,&encode_entities($line,'<>&"'));
1.46      albertel  554: 	}
1.43      albertel  555: 	close (DFH);
1.46      albertel  556:     } else { &log($fh,"No perm log\n") }
1.43      albertel  557: 
1.46      albertel  558:     my $fname="$perlvar{'lonDaemons'}/logs/lonnet.log";
1.73      albertel  559:     &rotate_logfile($fname,$fh,'lonnet log');
1.1       albertel  560: 
1.46      albertel  561:     &log($fh,"</pre>");
1.43      albertel  562:     &errout($fh);
1.46      albertel  563: }
                    564: 
1.73      albertel  565: sub rotate_other_logs {
                    566:     my ($fh) = @_;
                    567:     my $fname="$perlvar{'lonDaemons'}/logs/autoenroll.log";
                    568:     &rotate_logfile($fname,$fh,'Auto Enroll log');
                    569:     $fname="$perlvar{'lonDaemons'}/logs/autocreate.log";
                    570:     &rotate_logfile($fname,$fh,'Create Course log');
                    571:     $fname="$perlvar{'lonDaemons'}/logs/searchcat.log";
                    572:     &rotate_logfile($fname,$fh,'Search Cataloguing log');
                    573: }
                    574: 
1.43      albertel  575: # ----------------------------------------------------------------- Connections
1.46      albertel  576: sub test_connections {
1.72      albertel  577:     my ($fh)=@_;
1.48      albertel  578:     &log($fh,'<hr /><a name="connections" /><h2>Connections</h2>');
1.43      albertel  579:     print "testing connections\n";
1.48      albertel  580:     &log($fh,"<table border='2'>");
1.49      albertel  581:     my ($good,$bad)=(0,0);
1.72      albertel  582:     my %hostname = &Apache::lonnet::all_hostnames();
                    583:     foreach my $tryserver (sort(keys(%hostname))) {
1.43      albertel  584: 	print(".");
1.46      albertel  585: 	my $result;
1.72      albertel  586: 	my $answer=&Apache::lonnet::reply("ping",$tryserver);
1.43      albertel  587: 	if ($answer eq "$tryserver:$perlvar{'lonHostID'}") {
                    588: 	    $result="<b>ok</b>";
1.49      albertel  589: 	    $good++;
1.43      albertel  590: 	} else {
                    591: 	    $result=$answer;
                    592: 	    $warnings++;
1.49      albertel  593: 	    if ($answer eq 'con_lost') {
                    594: 		$bad++;
                    595: 		$warnings++;
1.50      albertel  596: 	    } else {
                    597: 		$good++; #self connection
1.49      albertel  598: 	    }
1.43      albertel  599: 	}
                    600: 	if ($answer =~ /con_lost/) { print(" $tryserver down\n"); }
1.46      albertel  601: 	&log($fh,"<tr><td>$tryserver</td><td>$result</td></tr>\n");
1.1       albertel  602:     }
1.46      albertel  603:     &log($fh,"</table>");
1.49      albertel  604:     print "\n$good good, $bad bad connections\n";
1.43      albertel  605:     &errout($fh);
1.46      albertel  606: }
                    607: 
                    608: 
1.1       albertel  609: # ------------------------------------------------------------ Delayed messages
1.46      albertel  610: sub check_delayed_msg {
1.72      albertel  611:     my ($fh)=@_;
1.48      albertel  612:     &log($fh,'<hr /><a name="delayed" /><h2>Delayed Messages</h2>');
1.43      albertel  613:     print "checking buffers\n";
1.46      albertel  614:     
                    615:     &log($fh,'<h3>Scanning Permanent Log</h3>');
1.1       albertel  616: 
1.46      albertel  617:     my $unsend=0;
1.1       albertel  618: 
1.46      albertel  619:     my $dfh=IO::File->new("$perlvar{'lonDaemons'}/logs/lonnet.perm.log");
                    620:     while (my $line=<$dfh>) {
                    621: 	my ($time,$sdf,$dserv,$dcmd)=split(/:/,$line);
                    622: 	if ($sdf eq 'F') { 
                    623: 	    my $local=localtime($time);
                    624: 	    &log($fh,"<b>Failed: $time, $dserv, $dcmd</b><br>");
                    625: 	    $warnings++;
1.43      albertel  626: 	}
1.46      albertel  627: 	if ($sdf eq 'S') { $unsend--; }
                    628: 	if ($sdf eq 'D') { $unsend++; }
1.1       albertel  629:     }
1.46      albertel  630: 
1.48      albertel  631:     &log($fh,"<p>Total unsend messages: <b>$unsend</b></p>\n");
1.43      albertel  632:     $warnings=$warnings+5*$unsend;
1.1       albertel  633: 
1.43      albertel  634:     if ($unsend) { $simplestatus{'unsend'}=$unsend; }
1.48      albertel  635:     &log($fh,"<h3>Outgoing Buffer</h3>\n<pre>");
1.68      www       636: # list directory with delayed messages and remember offline servers
                    637:     my %servers=();
1.43      albertel  638:     open (DFH,"ls -lF $perlvar{'lonSockDir'}/delayed|");
1.68      www       639:     while (my $line=<DFH>) {
                    640:         my ($server)=($line=~/\.(\w+)$/);
                    641:         if ($server) { $servers{$server}=1; }
1.48      albertel  642: 	&log($fh,&encode_entities($line,'<>&"'));
1.46      albertel  643:     }
1.48      albertel  644:     &log($fh,"</pre>\n");
1.43      albertel  645:     close (DFH);
1.68      www       646: # pong to all servers that have delayed messages
                    647: # this will trigger a reverse connection, which should flush the buffers
                    648:     foreach my $tryserver (keys %servers) {
1.72      albertel  649: 	my $answer=&Apache::lonnet::reply("pong",$tryserver);
1.69      www       650: 	&log($fh,"Pong to $tryserver: $answer<br />");
1.68      www       651:     }
1.46      albertel  652: }
1.1       albertel  653: 
1.46      albertel  654: sub finish_logging {
                    655:     my ($fh)=@_;
1.48      albertel  656:     &log($fh,"<a name='errcount' />\n");
1.43      albertel  657:     $totalcount=$notices+4*$warnings+100*$errors;
                    658:     &errout($fh);
1.46      albertel  659:     &log($fh,"<h1>Total Error Count: $totalcount</h1>");
                    660:     my $now=time;
                    661:     my $date=localtime($now);
1.48      albertel  662:     &log($fh,"<hr />$date ($now)</body></html>\n");
1.43      albertel  663:     print "lon-status webpage updated\n";
                    664:     $fh->close();
1.46      albertel  665: 
                    666:     if ($errors) { $simplestatus{'errors'}=$errors; }
                    667:     if ($warnings) { $simplestatus{'warnings'}=$warnings; }
                    668:     if ($notices) { $simplestatus{'notices'}=$notices; }
                    669:     $simplestatus{'time'}=time;
1.1       albertel  670: }
                    671: 
1.46      albertel  672: sub log_simplestatus {
1.73      albertel  673:     rename("$statusdir/newstatus.html","$statusdir/index.html");
1.46      albertel  674:     
1.43      albertel  675:     my $sfh=IO::File->new(">$statusdir/loncron_simple.txt");
                    676:     foreach (keys %simplestatus) {
                    677: 	print $sfh $_.'='.$simplestatus{$_}.'&';
                    678:     }
                    679:     print $sfh "\n";
                    680:     $sfh->close();
1.41      www       681: }
1.46      albertel  682: 
                    683: sub send_mail {
1.43      albertel  684:     print "sending mail\n";
1.79      raeburn   685:     my $defdom = $perlvar{'lonDefDomain'};
                    686:     my $origmail = $perlvar{'lonAdmEMail'};
1.78      raeburn   687:     my $emailto = &Apache::loncommon::build_recipient_list(undef,
                    688:                                    'lonstatusmail',$defdom,$origmail);
1.54      www       689:     if ($totalcount>2500) {
1.43      albertel  690: 	$emailto.=",$perlvar{'lonSysEMail'}";
                    691:     }
1.46      albertel  692:     my $subj="LON: $perlvar{'lonHostID'} E:$errors W:$warnings N:$notices"; 
1.52      albertel  693: 
1.58      albertel  694:     my $result=system("metasend -b -S 4000000 -t $emailto -s '$subj' -f $statusdir/index.html -m text/html >& /dev/null");
1.52      albertel  695:     if ($result != 0) {
                    696: 	$result=system("mail -s '$subj' $emailto < $statusdir/index.html");
                    697:     }
1.1       albertel  698: }
1.46      albertel  699: 
1.49      albertel  700: sub usage {
                    701:     print(<<USAGE);
                    702: loncron - housekeeping program that checks up on various parts of Lon-CAPA
                    703: 
                    704: Options:
1.71      albertel  705:    --help     Display 
1.49      albertel  706:    --noemail  Do not send the status email
                    707:    --justcheckconnections  Only check the current status of the lonc/d
                    708:                                 connections, do not send emails do not
                    709:                                 check if the daemons are running, do not
                    710:                                 generate lon-status
                    711:    --justcheckdaemons      Only check that all of the Lon-CAPA daemons are
                    712:                                 running, do not send emails do not
                    713:                                 check the lonc/d connections, do not
                    714:                                 generate lon-status
1.59      albertel  715:    --justreload            Only tell the daemons to reload the config files,
                    716: 				do not send emails do not
                    717:                                 check if the daemons are running, do not
                    718:                                 generate lon-status
1.49      albertel  719:                            
                    720: USAGE
                    721: }
                    722: 
1.46      albertel  723: # ================================================================ Main Program
                    724: sub main () {
1.71      albertel  725:     my ($help,$justcheckdaemons,$noemail,$justcheckconnections,
1.59      albertel  726: 	$justreload);
1.49      albertel  727:     &GetOptions("help"                 => \$help,
                    728: 		"justcheckdaemons"     => \$justcheckdaemons,
                    729: 		"noemail"              => \$noemail,
1.59      albertel  730: 		"justcheckconnections" => \$justcheckconnections,
                    731: 		"justreload"           => \$justreload
1.49      albertel  732: 		);
                    733:     if ($help) { &usage(); return; }
1.46      albertel  734: # --------------------------------- Read loncapa_apache.conf and loncapa.conf
                    735:     my $perlvarref=LONCAPA::Configuration::read_conf('loncapa.conf');
                    736:     %perlvar=%{$perlvarref};
                    737:     undef $perlvarref;
                    738:     delete $perlvar{'lonReceipt'}; # remove since sensitive and not needed
                    739:     delete $perlvar{'lonSqlAccess'}; # remove since sensitive and not needed
1.75      albertel  740:     chdir($perlvar{'lonDaemons'});
1.46      albertel  741: # --------------------------------------- Make sure that LON-CAPA is configured
                    742: # I only test for one thing here (lonHostID).  This is just a safeguard.
                    743:     if ('{[[[[lonHostID]]]]}' eq $perlvar{'lonHostID'}) {
                    744: 	print("Unconfigured machine.\n");
                    745: 	my $emailto=$perlvar{'lonSysEMail'};
                    746: 	my $hostname=`/bin/hostname`;
                    747: 	chop $hostname;
                    748: 	$hostname=~s/[^\w\.]//g; # make sure is safe to pass through shell
                    749: 	my $subj="LON: Unconfigured machine $hostname";
                    750: 	system("echo 'Unconfigured machine $hostname.' |\
                    751:  mailto $emailto -s '$subj' > /dev/null");
                    752: 	exit 1;
                    753:     }
                    754: 
                    755: # ----------------------------- Make sure this process is running from user=www
                    756:     my $wwwid=getpwnam('www');
                    757:     if ($wwwid!=$<) {
                    758: 	print("User ID mismatch.  This program must be run as user 'www'\n");
                    759: 	my $emailto="$perlvar{'lonAdmEMail'},$perlvar{'lonSysEMail'}";
                    760: 	my $subj="LON: $perlvar{'lonHostID'} User ID mismatch";
                    761: 	system("echo 'User ID mismatch.  loncron must be run as user www.' |\
                    762:  mailto $emailto -s '$subj' > /dev/null");
                    763: 	exit 1;
                    764:     }
                    765: 
1.72      albertel  766: # -------------------------------------------- Force reload of host information
                    767:     &Apache::lonnet::load_hosts_tab(1);
                    768:     &Apache::lonnet::load_domain_tab(1);
                    769:     &Apache::lonnet::get_iphost(1);
1.46      albertel  770: 
1.81      raeburn   771: # ----------------------------------------- Force firewall update for lond port  
                    772: 
                    773:     if ((!$justcheckdaemons) && (!$justreload)) {
                    774:         my $now = time;
                    775:         my $tmpfile = $perlvar{'lonDaemons'}.'/tmp/lciptables_iphost_'.
                    776:                       $now.$$.int(rand(10000));
                    777:         if (open(my $fh,">$tmpfile")) {
                    778:             my %iphosts = &Apache::lonnet::get_iphost();
                    779:             foreach my $key (keys(%iphosts)) {
                    780:                 print $fh "$key\n";
                    781:             }
                    782:             close($fh);
                    783:             my $execpath = $perlvar{'lonDaemons'}.'/lciptables';
                    784:             system("$execpath $tmpfile");
                    785:             unlink($fh);
                    786:         }
                    787:     }
                    788: 
1.46      albertel  789: # ---------------------------------------------------------------- Start report
                    790: 
                    791:     $errors=0;
                    792:     $warnings=0;
                    793:     $notices=0;
                    794: 
                    795: 	
1.49      albertel  796:     my $fh;
1.59      albertel  797:     if (!$justcheckdaemons && !$justcheckconnections && !$justreload) {
1.72      albertel  798: 	$fh=&start_logging();
1.49      albertel  799: 
                    800: 	&log_machine_info($fh);
                    801: 	&clean_tmp($fh);
                    802: 	&clean_lonIDs($fh);
                    803: 	&check_httpd_logs($fh);
                    804: 	&rotate_lonnet_logs($fh);
1.73      albertel  805: 	&rotate_other_logs($fh);
1.49      albertel  806:     }
1.59      albertel  807:     if (!$justcheckconnections && !$justreload) {
1.76      albertel  808: 	&checkon_daemon($fh,'lonmemcached',40000);
1.49      albertel  809: 	&checkon_daemon($fh,'lonsql',200000);
1.63      albertel  810: 	if ( &checkon_daemon($fh,'lond',40000,'USR1') eq 'running') {
                    811: 	    &checkon_daemon($fh,'lond',40000,'USR2');
                    812: 	}
1.71      albertel  813: 	&checkon_daemon($fh,'lonc',40000,'USR1');
1.70      raeburn   814:         &checkon_daemon($fh,'lonmaxima',40000);
1.80      www       815:         &checkon_daemon($fh,'lonr',40000);
1.49      albertel  816:     }
1.59      albertel  817:     if ($justreload) {
                    818: 	&checkon_daemon($fh,'lond',40000,'USR2');
1.71      albertel  819: 	&checkon_daemon($fh,'lonc',40000,'USR2');
1.59      albertel  820:     }
1.63      albertel  821:     if ($justcheckconnections) {
1.72      albertel  822: 	&test_connections($fh);
1.49      albertel  823:     }
1.59      albertel  824:     if (!$justcheckdaemons && !$justcheckconnections && !$justreload) {
1.72      albertel  825: 	&check_delayed_msg($fh);
1.49      albertel  826: 	&finish_logging($fh);
                    827: 	&log_simplestatus();
                    828: 	
                    829: 	if ($totalcount>200 && !$noemail) { &send_mail(); }
                    830:     }
1.46      albertel  831: }
                    832: 
                    833: &main();
1.1       albertel  834: 1;
                    835: 
                    836: 
                    837: 
                    838: 
                    839: 
                    840: 
                    841: 
                    842: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>
500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.