--- loncom/loncron 2020/05/06 14:40:08 1.103.2.7
+++ loncom/loncron 2018/11/06 15:37:42 1.113
@@ -2,7 +2,7 @@
# Housekeeping program, started by cron, loncontrol and loncron.pl
#
-# $Id: loncron,v 1.103.2.7 2020/05/06 14:40:08 raeburn Exp $
+# $Id: loncron,v 1.113 2018/11/06 15:37:42 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -41,9 +41,8 @@ use IO::File;
use IO::Socket;
use HTML::Entities;
use Getopt::Long;
-use File::Copy;
-use Sys::Hostname::FQDN();
-
+use GDBM_File;
+use Storable qw(thaw);
#globals
use vars qw (%perlvar %simplestatus $errors $warnings $notices $totalcount);
@@ -117,7 +116,7 @@ sub checkon_daemon {
if ($fh) {
if (-e "$perlvar{'lonDaemons'}/logs/$daemon.log"){
if (open(DFH,"tail -n25 $perlvar{'lonDaemons'}/logs/$daemon.log|")) {
- while (my $line=) {
+ while (my $line=) {
&log($fh,"$line");
if ($line=~/INFO/) { $notices++; }
if ($line=~/WARNING/) { $notices++; }
@@ -128,7 +127,7 @@ sub checkon_daemon {
}
&log($fh,"
");
}
-
+
my $pidfile="$perlvar{'lonDaemons'}/logs/$daemon.pid";
my $restartflag=1;
@@ -169,6 +168,9 @@ sub checkon_daemon {
&log($fh,unlink($pidfile).' - '.
`killall -9 $kadaemon 2>&1`.
'
');
+ if ($kadaemon eq 'loncnew') {
+ &clean_lonc_childpids();
+ }
&log($fh,"$daemon not running, trying to start
");
if (&start_daemon($fh,$daemon,$pidfile,$args)) {
@@ -207,8 +209,8 @@ sub checkon_daemon {
close (DFH);
}
&log($fh,"");
- }
- }
+ }
+ }
}
my $fname="$perlvar{'lonDaemons'}/logs/$daemon.log";
@@ -490,71 +492,24 @@ sub clean_lonIDs {
my $cleaned=0;
my $active=0;
while (my $fname=<$perlvar{'lonIDsDir'}/*>) {
- my $now=time;
- if (-l $fname) {
- my $linkfname = readlink($fname);
- if (-f $linkfname) {
- if ($linkfname =~ m{^$perlvar{'lonIDsDir'}/[^/]+\.id$}) {
- my @data = stat($linkfname);
- my $mtime = $data[9];
- my $since=$now-$mtime;
- if ($since>$perlvar{'lonExpire'}) {
- if (unlink($linkfname)) {
- $cleaned++;
- &log($fh,"Unlinking $linkfname
");
- unlink($fname);
- }
- }
- }
- } else {
- unlink($fname);
- }
- } elsif (-f $fname) {
- my @data = stat($fname);
- my $mtime = $data[9];
- my $since=$now-$mtime;
- if ($since>$perlvar{'lonExpire'}) {
- if (unlink($fname)) {
- $cleaned++;
- &log($fh,"Unlinking $fname
");
- }
- } else {
- $active++;
- }
- }
+ my ($dev,$ino,$mode,$nlink,
+ $uid,$gid,$rdev,$size,
+ $atime,$mtime,$ctime,
+ $blksize,$blocks)=stat($fname);
+ my $now=time;
+ my $since=$now-$mtime;
+ if ($since>$perlvar{'lonExpire'}) {
+ $cleaned++;
+ &log($fh,"Unlinking $fname
");
+ unlink("$fname");
+ } else {
+ $active++;
+ }
}
&log($fh,"Cleaned up ".$cleaned." stale session token(s).
");
&log($fh,"$active open session(s)
");
}
-# -------------------------------------------------------- clean out balanceIDs
-
-sub clean_balanceIDs {
- my ($fh)=@_;
- &log($fh,'
Session Tokens
');
- my $cleaned=0;
- my $active=0;
- if (-d $perlvar{'lonBalanceDir'}) {
- while (my $fname=<$perlvar{'balanceDir'}/*.id>) {
- my ($dev,$ino,$mode,$nlink,
- $uid,$gid,$rdev,$size,
- $atime,$mtime,$ctime,
- $blksize,$blocks)=stat($fname);
- my $now=time;
- my $since=$now-$mtime;
- if ($since>$perlvar{'lonExpire'}) {
- $cleaned++;
- &log($fh,"Unlinking $fname
");
- unlink("$fname");
- } else {
- $active++;
- }
- }
- }
- &log($fh,"Cleaned up ".$cleaned." stale balancer files
");
- &log($fh,"$active unexpired balancer files
");
-}
-
# ------------------------------------------------ clean out webDAV Session IDs
sub clean_webDAV_sessionIDs {
my ($fh)=@_;
@@ -758,9 +713,9 @@ sub check_delayed_msg {
}
sub finish_logging {
- my ($fh)=@_;
+ my ($fh,%weights)=@_;
&log($fh,"\n");
- $totalcount=$notices+4*$warnings+100*$errors;
+ $totalcount=($weights{'N'}*$notices)+($weights{'W'}*$warnings)+($weights{'E'}*$errors);
&errout($fh);
&log($fh,"Total Error Count: $totalcount
");
my $now=time;
@@ -874,87 +829,256 @@ sub write_checksums {
return;
}
-sub write_hostips {
- my $lontabdir = $perlvar{'lonTabDir'};
- my $defdom = $perlvar{'lonDefDomain'};
- my $lonhost = $perlvar{'lonHostID'};
- my $newfile = "$lontabdir/currhostips.tab";
- my $oldfile = "$lontabdir/prevhostips.tab";
- my (%prevhosts,%currhosts,%ipchange);
- if ((-e $newfile) && (-s $newfile)) {
- move($newfile,$oldfile);
- chmod(0644,$oldfile);
- if (open(my $fh,'<',$oldfile)) {
- while (my $line=<$fh>) {
- chomp($line);
- if ($line =~ /^([^:]+):([\d.]+)$/) {
- $prevhosts{$1} = $2;
+sub clean_nosslverify {
+ my ($fh) = @_;
+ my %unlinked;
+ if (-d "$perlvar{'lonSockDir'}/nosslverify") {
+ if (opendir(my $dh,"$perlvar{'lonSockDir'}/nosslverify")) {
+ while (my $fname=readdir($dh)) {
+ next if ($fname =~ /^\.+$/);
+ if (unlink("/home/httpd/sockets/nosslverify/$fname")) {
+ &log($fh,"Unlinking $fname
");
+ $unlinked{$fname} = 1;
}
}
- close($fh);
+ closedir($dh);
}
}
- my ($ip_info,$cached) =
- &Apache::lonnet::is_cached_new('iphost','iphost');
- if (!$cached) {
- &Apache::lonnet::get_iphost();
- ($ip_info,$cached) =
- &Apache::lonnet::is_cached_new('iphost','iphost');
- }
- if (ref($ip_info) eq 'ARRAY') {
- %currhosts = %{$ip_info->[1]};
- if (open(my $fh,'>',$newfile)) {
- foreach my $key (keys(%currhosts)) {
- print $fh "$key:$currhosts{$key}\n";
+ &log($fh,"Removed ".scalar(keys(%unlinked))." nosslverify clients
");
+ return %unlinked;
+}
+sub clean_lonc_childpids {
+ my $childpiddir = "$perlvar{'lonDocRoot'}/lon-status/loncchld";
+ if (-d $childpiddir) {
+ if (opendir(my $dh,$childpiddir)) {
+ while (my $fname=readdir($dh)) {
+ next if ($fname =~ /^\.+$/);
+ unlink("$childpiddir/$fname");
}
- close($fh);
- chmod(0644,$newfile);
+ closedir($dh);
+ }
+ }
+}
+
+sub write_connection_config {
+ my ($domconf,%connectssl,%changes);
+ $domconf = &get_domain_config();
+ if (ref($domconf) eq 'HASH') {
+ if (ref($domconf->{'ssl'}) eq 'HASH') {
+ foreach my $connect ('connto','connfrom') {
+ if (ref($domconf->{'ssl'}->{$connect}) eq 'HASH') {
+ my ($sslreq,$sslnoreq,$currsetting);
+ my %contypes;
+ foreach my $type ('dom','intdom','other') {
+ $connectssl{$connect.'_'.$type} = $domconf->{'ssl'}->{$connect}->{$type};
+ }
+ }
+ }
+ }
+ if (keys(%connectssl)) {
+ my %currconf;
+ if (open(my $fh,'<',"$perlvar{'lonTabDir'}/connectionrules.tab")) {
+ while (my $line = <$fh>) {
+ chomp($line);
+ my ($name,$value) = split(/=/,$line);
+ if ($value =~ /^(?:no|yes|req)$/) {
+ if ($name =~ /^conn(to|from)_(dom|intdom|other)$/) {
+ $currconf{$name} = $value;
+ }
+ }
+ }
+ close($fh);
+ }
+ if (open(my $fh,'>',"$perlvar{'lonTabDir'}/connectionrules.tab")) {
+ my $count = 0;
+ foreach my $key (sort(keys(%connectssl))) {
+ print $fh "$key=$connectssl{$key}\n";
+ if (exists($currconf{$key})) {
+ unless ($currconf{$key} eq $connectssl{$key}) {
+ $changes{$key} = 1;
+ }
+ } else {
+ $changes{$key} = 1;
+ }
+ $count ++;
+ }
+ close($fh);
+ print "Completed writing SSL options for lonc/lond for $count items.\n";
+ }
+ } else {
+ print "Writing of SSL options skipped - no connection rules in domain configuration.\n";
}
+ } else {
+ print "Retrieval of SSL options for lonc/lond skipped - no configuration data available for domain.\n";
}
- if (keys(%prevhosts) && keys(%currhosts)) {
- foreach my $key (keys(%prevhosts)) {
- unless ($currhosts{$key} eq $prevhosts{$key}) {
- $ipchange{$key} = $prevhosts{$key}.' | '.$currhosts{$key};
+ return %changes;
+}
+
+sub get_domain_config {
+ my ($dom,$primlibserv,$isprimary,$url,%confhash);
+ $dom = $perlvar{'lonDefDomain'};
+ $primlibserv = &Apache::lonnet::domain($dom,'primary');
+ if ($primlibserv eq $perlvar{'lonHostID'}) {
+ $isprimary = 1;
+ } elsif ($primlibserv ne '') {
+ my $protocol = $Apache::lonnet::protocol{$primlibserv};
+ my $hostname = &Apache::lonnet::hostname($primlibserv);
+ unless ($protocol eq 'https') {
+ $protocol = 'http';
+ }
+ $url = $protocol.'://'.$hostname.'/cgi-bin/listdomconfig.pl';
+ }
+ if ($isprimary) {
+ my $lonusersdir = $perlvar{'lonUsersDir'};
+ my $fname = $lonusersdir.'/'.$dom.'/configuration.db';
+ if (-e $fname) {
+ my $dbref=&LONCAPA::locking_hash_tie($fname,&GDBM_READER());
+ if (ref($dbref) eq 'HASH') {
+ foreach my $key (sort(keys(%{$dbref}))) {
+ my $value = $dbref->{$key};
+ if ($value =~ s/^__FROZEN__//) {
+ $value = thaw(&LONCAPA::unescape($value));
+ } else {
+ $value = &LONCAPA::unescape($value);
+ }
+ $confhash{$key} = $value;
+ }
+ &LONCAPA::locking_hash_untie($dbref);
}
}
- foreach my $key (keys(%currhosts)) {
- unless ($currhosts{$key} eq $prevhosts{$key}) {
- $ipchange{$key} = $prevhosts{$key}.' | '.$currhosts{$key};
+ } else {
+ if (open(PIPE,"wget --no-check-certificate '$url?primary=$primlibserv&format=raw' |")) {
+ my $config = '';
+ while () {
+ $config .= $_;
+ }
+ close(PIPE);
+ if ($config) {
+ my @pairs=split(/\&/,$config);
+ foreach my $item (@pairs) {
+ my ($key,$value)=split(/=/,$item,2);
+ my $what = &LONCAPA::unescape($key);
+ if ($value =~ s/^__FROZEN__//) {
+ $value = thaw(&LONCAPA::unescape($value));
+ } else {
+ $value = &LONCAPA::unescape($value);
+ }
+ $confhash{$what}=$value;
+ }
}
}
}
- if (&Apache::lonnet::domain($defdom,'primary') eq $lonhost) {
- if (keys(%ipchange)) {
- if (open(my $fh,'>>',$perlvar{'lonDaemons'}.'/logs/hostip.log')) {
- print $fh "********************\n".localtime(time).' Changes --'."\n".
- "| Hostname | Previous IP | New IP |\n".
- " --------------------------------- \n";
- foreach my $hostname (sort(keys(%ipchange))) {
- print $fh "| $hostname | $ipchange{$hostname} |\n";
+ return \%confhash;
+}
+
+sub write_hosttypes {
+ my %intdom = &Apache::lonnet::all_host_intdom();
+ my %hostdom = &Apache::lonnet::all_host_domain();
+ my $dom = $hostdom{$perlvar{'lonHostID'}};
+ my $internetdom = $intdom{$perlvar{'lonHostID'}};
+ my %changes;
+ if (($dom ne '') && ($internetdom ne '')) {
+ if (keys(%hostdom)) {
+ my %currhosttypes;
+ if (open(my $fh,'<',"$perlvar{'lonTabDir'}/hosttypes.tab")) {
+ while (my $line = <$fh>) {
+ chomp($line);
+ my ($name,$value) = split(/:/,$line);
+ if (($name ne '') && ($value =~ /^(dom|intdom|other)$/)) {
+ $currhosttypes{$name} = $value;
+ }
}
- print $fh "\n*******************\n\n";
close($fh);
}
- my $emailto = &Apache::loncommon::build_recipient_list(undef,
- 'hostipmail',$defdom);
- if ($emailto) {
- my $subject = "LON-CAPA Hostname to IP change ($perlvar{'lonHostID'})";
- my $chgmail = "To: $emailto\n".
- "Subject: $subject\n".
- "Content-type: text/plain\; charset=UTF-8\n".
- "MIME-Version: 1.0\n\n".
- "Host/IP changes\n".
- " \n".
- "| Hostname | Previous IP | New IP |\n".
- " --------------------------------- \n";
- foreach my $hostname (sort(keys(%ipchange))) {
- $chgmail .= "| $hostname | $ipchange{$hostname} |\n";
+ if (open(my $fh,'>',"$perlvar{'lonTabDir'}/hosttypes.tab")) {
+ my $count = 0;
+ foreach my $lonid (sort(keys(%hostdom))) {
+ my $type = 'other';
+ if ($hostdom{$lonid} eq $dom) {
+ $type = 'dom';
+ } elsif ($intdom{$lonid} eq $internetdom) {
+ $type = 'intdom';
+ }
+ print $fh "$lonid:$type\n";
+ if (exists($currhosttypes{$lonid})) {
+ if ($type ne $currhosttypes{$lonid}) {
+ $changes{$lonid} = 1;
+ }
+ } else {
+ $changes{$lonid} = 1;
+ }
+ $count ++;
}
- $chgmail .= "\n\n";
- if (open(my $mailh, "|/usr/lib/sendmail -oi -t -odb")) {
- print $mailh $chgmail;
- close($mailh);
- print "Sending mail notification of hostname/IP changes.\n";
+ close($fh);
+ print "Completed writing host type data for $count hosts.\n";
+ }
+ } else {
+ print "Writing of host types skipped - no hosts found.\n";
+ }
+ } else {
+ print "Writing of host types skipped - could not determine this host's LON-CAPA domain or 'internet' domain.\n";
+ }
+ return %changes;
+}
+
+sub update_revocation_list {
+ my ($result,$changed) = &Apache::lonnet::fetch_crl_pemfile();
+ if ($result eq 'ok') {
+ print "Certificate Revocation List (from CA) updated.\n";
+ } else {
+ print "Certificate Revocation List from (CA) not updated.\n";
+ }
+ return $changed;
+}
+
+sub reset_nosslverify_pids {
+ my ($fh,%sslrem) = @_;
+ &checkon_daemon($fh,'lond',40000,'USR2');
+ my $loncpidfile="$perlvar{'lonDaemons'}/logs/lonc.pid";
+ my $loncppid;
+ if ((-e $loncpidfile) && (open(my $pfh,'<',$loncpidfile))) {
+ $loncppid=<$pfh>;
+ chomp($loncppid);
+ close($pfh);
+ if ($loncppid =~ /^\d+$/) {
+ my %pids_by_host;
+ my $docdir = $perlvar{'lonDocRoot'};
+ if (-d "$docdir/lon-status/loncchld") {
+ if (opendir(my $dh,"$docdir/lon-status/loncchld")) {
+ while (my $file = readdir($dh)) {
+ next if ($file =~ /^\./);
+ if (open(my $fh,'<',"$docdir/lon-status/loncchld/$file")) {
+ my $record = <$fh>;
+ chomp($record);
+ close($fh);
+ my ($remotehost,$authmode) = split(/:/,$record);
+ $pids_by_host{$remotehost}{$authmode}{$file} = 1;
+ }
+ }
+ closedir($dh);
+ if (keys(%pids_by_host)) {
+ foreach my $host (keys(%pids_by_host)) {
+ if ($sslrem{$host}) {
+ if (ref($pids_by_host{$host}) eq 'HASH') {
+ if (ref($pids_by_host{$host}{'insecure'}) eq 'HASH') {
+ if (keys(%{$pids_by_host{$host}{'insecure'}})) {
+ foreach my $pid (keys(%{$pids_by_host{$host}{'insecure'}})) {
+ if (open(PIPE,"ps -o ppid= -p $pid |")) {
+ my $ppid = ;
+ chomp($ppid);
+ close(PIPE);
+ $ppid =~ s/(^\s+|\s+$)//g;
+ if (($ppid == $loncppid) && (kill 0 => $pid)) {
+ kill QUIT => $pid;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
}
}
}
@@ -963,11 +1087,12 @@ sub write_hostips {
}
sub send_mail {
+ my ($sysmail,$reportstatus) = @_;
my $defdom = $perlvar{'lonDefDomain'};
my $origmail = $perlvar{'lonAdmEMail'};
my $emailto = &Apache::loncommon::build_recipient_list(undef,
'lonstatusmail',$defdom,$origmail);
- if ($totalcount>2500) {
+ if (($totalcount>$sysmail) && ($reportstatus)) {
$emailto.=",$perlvar{'lonSysEMail'}";
}
my $from;
@@ -1020,23 +1145,19 @@ Options:
do not send emails do not
check if the daemons are running, do not
generate lon-status
- --justiptables Only update the dynamic iptables rules for the
- lond port; do not send emails, do not
- check if the daemons are running, do not
- generate lon-status
+
USAGE
}
# ================================================================ Main Program
sub main () {
my ($help,$justcheckdaemons,$noemail,$justcheckconnections,
- $justreload,$justiptables);
+ $justreload);
&GetOptions("help" => \$help,
"justcheckdaemons" => \$justcheckdaemons,
"noemail" => \$noemail,
"justcheckconnections" => \$justcheckconnections,
- "justreload" => \$justreload,
- "justiptables" => \$justiptables
+ "justreload" => \$justreload
);
if ($help) { &usage(); return; }
# --------------------------------- Read loncapa_apache.conf and loncapa.conf
@@ -1051,10 +1172,9 @@ sub main () {
if ('{[[[[lonHostID]]]]}' eq $perlvar{'lonHostID'}) {
print("Unconfigured machine.\n");
my $emailto=$perlvar{'lonSysEMail'};
- my $hostname = Sys::Hostname::FQDN::fqdn();
- $hostname=~s/\.+/./g;
- $hostname=~s/\-+/-/g;
- $hostname=~s/[^\w\.-]//g; # make sure is safe to pass through shell
+ my $hostname=`/bin/hostname`;
+ chop $hostname;
+ $hostname=~s/[^\w\.]//g; # make sure is safe to pass through shell
my $subj="LON: Unconfigured machine $hostname";
system("echo 'Unconfigured machine $hostname.' |".
" mail -s '$subj' $emailto > /dev/null");
@@ -1087,11 +1207,9 @@ sub main () {
}
}
}
- if (!$justiptables) {
- &Apache::lonnet::load_hosts_tab(1,$nomemcache);
- &Apache::lonnet::load_domain_tab(1,$nomemcache);
- &Apache::lonnet::get_iphost(1,$nomemcache);
- }
+ &Apache::lonnet::load_hosts_tab(1,$nomemcache);
+ &Apache::lonnet::load_domain_tab(1,$nomemcache);
+ &Apache::lonnet::get_iphost(1,$nomemcache);
# ----------------------------------------- Force firewall update for lond port
@@ -1122,19 +1240,18 @@ sub main () {
my $fh;
- if (!$justcheckdaemons && !$justcheckconnections && !$justreload && !$justiptables) {
+ if (!$justcheckdaemons && !$justcheckconnections && !$justreload) {
$fh=&start_logging();
&log_machine_info($fh);
&clean_tmp($fh);
&clean_lonIDs($fh);
- &clean_balanceIDs($fh);
&clean_webDAV_sessionIDs($fh);
&check_httpd_logs($fh);
&rotate_lonnet_logs($fh);
&rotate_other_logs($fh);
}
- if (!$justcheckconnections && !$justreload && !$justiptables) {
+ if (!$justcheckconnections && !$justreload) {
&checkon_daemon($fh,'lonmemcached',40000);
&checkon_daemon($fh,'lonsql',200000);
if ( &checkon_daemon($fh,'lond',40000,'USR1') eq 'running') {
@@ -1145,21 +1262,62 @@ sub main () {
&checkon_daemon($fh,'lonr',40000);
}
if ($justreload) {
+ &clean_nosslverify($fh);
+ &write_connection_config();
+ &write_hosttypes();
+ &update_revocation_list();
&checkon_daemon($fh,'lond',40000,'USR2');
&checkon_daemon($fh,'lonc',40000,'USR2');
}
if ($justcheckconnections) {
&test_connections($fh);
}
- if (!$justcheckdaemons && !$justcheckconnections && !$justreload && !$justiptables) {
+ if (!$justcheckdaemons && !$justcheckconnections && !$justreload) {
&check_delayed_msg($fh);
- &finish_logging($fh);
&log_simplestatus();
&write_loncaparevs();
&write_serverhomeIDs();
&write_checksums();
- &write_hostips();
- if ($totalcount>200 && !$noemail) { &send_mail(); }
+ my %sslrem = &clean_nosslverify($fh);
+ my %conchgs = &write_connection_config();
+ my %hosttypechgs = &write_hosttypes();
+ my $hadcrlchg = &update_revocation_list();
+ if ((keys(%conchgs) > 0) || (keys(%hosttypechgs) > 0) ||
+ $hadcrlchg || (keys(%sslrem) > 0)) {
+ &checkon_daemon($fh,'lond',40000,'USR2');
+ &reset_nosslverify_pids($fh,%sslrem);
+ }
+ my $domconf = &get_domain_config();
+ my ($defaults,$names) = &Apache::loncommon::lon_status_items();
+ my (%weights,$threshold);
+ foreach my $type ('E','W','N') {
+ $weights{$type} = $defaults->{$type};
+ }
+ my $threshold = $defaults->{'threshold'};
+ my $sysmail = $defaults->{'sysmail'};
+ my $reportstatus = 1;
+ if (ref($domconf->{'contacts'}) eq 'HASH') {
+ if ($domconf->{'contacts'}{'reportstatus'} == 0) {
+ $reportstatus = 0;
+ }
+ if (ref($domconf->{'contacts'}{'lonstatus'}) eq 'HASH') {
+ if (ref($domconf->{'contacts'}{'lonstatus'}{weights}) eq 'HASH') {
+ foreach my $type ('E','W','N') {
+ if (exists($domconf->{'contacts'}{'lonstatus'}{weights}{$type})) {
+ $weights{$type} = $domconf->{'contacts'}{'lonstatus'}{weights}{$type};
+ }
+ }
+ }
+ }
+ if (exists($domconf->{'contacts'}{'lonstatus'}{'threshold'})) {
+ $threshold = $domconf->{'contacts'}{'lonstatus'}{'threshold'};
+ }
+ if (exists($domconf->{'contacts'}{'lonstatus'}{'sysmail'})) {
+ $sysmail = $domconf->{'contacts'}{'lonstatus'}{'sysmail'};
+ }
+ }
+ &finish_logging($fh,%weights);
+ if ($totalcount>$threshold && !$noemail) { &send_mail($sysmail,$reportstatus); }
}
}