Annotation of loncom/init.d/loncontrol, revision 1.36

1.1       harris41    1: #!/usr/bin/perl
1.2       harris41    2: #
1.36    ! raeburn     3: # $Id: loncontrol,v 1.35 2009/04/22 14:58:59 raeburn Exp $
1.23      matthew     4: #
1.6       harris41    5: # The LearningOnline Network with CAPA
                      6: #
1.21      matthew     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/
                     28: #
1.2       harris41   29: # Startup script for the LON-CAPA network processes
1.6       harris41   30: #
1.7       harris41   31: 
1.3       harris41   32: # chkconfig: 345 95 5
1.21      matthew    33: # description: LON-CAPA is a "network of knowledge".  It is used to \
1.6       harris41   34: # distribute knowledge resources and instructional management.
1.35      raeburn    35: # processnames: lonc, lond, lonsql, lonmaxima, lonr
1.2       harris41   36: # pidfiles: /home/httpd/perl/logs/lon*.pid
1.7       harris41   37: # config: /etc/httpd/conf/loncapa.conf
1.2       harris41   38: # config: /home/httpd/lonTabs/hosts.tab
                     39: # config: /home/httpd/lonTabs/spare.tab
1.31      albertel   40: # SuSE chkconfig/insserv info
                     41: ### BEGIN INIT INFO
                     42: # Provides:       loncapa
                     43: # Required-Start: mysql apache2 $network $remote_fs
                     44: # Required-Stop:
                     45: # Default-Start:  3 4 5
                     46: # Default-Stop:
                     47: # Description:    Starts the LON-CAPA services
                     48: ### END INIT INFO
                     49: 
1.34      raeburn    50: use strict;
                     51: use lib '/home/httpd/lib/perl/';
                     52: use LONCAPA::Configuration;
1.36    ! raeburn    53: use Apache::lonnet;
1.2       harris41   54: 
1.34      raeburn    55: my $command=$ARGV[0]; $command=~s/[^a-z]//g;
1.1       harris41   56: 
                     57: $ENV{'PATH'}="/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin";
                     58: $ENV{'BASH_ENV'}="";
                     59: 
1.20      matthew    60: { # Firewall variable scoping
                     61:     # Firewall code is based on the code in FC2 /etc/init.d/ntpd
                     62:     my $fw_chain = 'RH-Firewall-1-INPUT';
                     63:     my $iptables = '/sbin/iptables';
1.27      albertel   64:     if (! -e $iptables) {
                     65: 	$iptables = '/usr/sbin/iptables';
1.34      raeburn    66: 	if (!-e $iptables) {
1.27      albertel   67: 	    print("Unable to find iptables command\n");
                     68: 	}
                     69:     }
1.34      raeburn    70:     my $suse_config = "/etc/sysconfig/SuSEfirewall2";
1.36    ! raeburn    71:     if (-e $suse_config) {
        !            72:         $fw_chain = 'input_ext';
        !            73:     } else {
1.34      raeburn    74:         if (!-e '/etc/sysconfig/iptables') {
                     75:             print("Unable to find iptables file containing static definitions\n");
                     76:         }
                     77:     }
                     78:     my $lond_port = &get_lond_port();
                     79:     if (!$lond_port) {
                     80:         print("Unable to determine lond port number from LON-CAPA configuration.\n");
                     81:     }
1.20      matthew    82: 
                     83: sub firewall_open_port {
1.34      raeburn    84:     return 'inactive firewall' if (! &firewall_is_active);
                     85:     return 'port number unknown' if !$lond_port;
                     86:     my @opened;
1.36    ! raeburn    87:     if (! `$iptables -L -n 2>/dev/null | grep $fw_chain | wc -l`) {
        !            88:         return 'Expected chain "'.$fw_chain.'" missing from iptables'."\n";
        !            89:     }
        !            90:     # iptables is running with expected chain
        !            91:     #
        !            92:     # For lond port, restrict the servers allowed to attempt to communicate
        !            93:     # to include only source IPs in the LON-CAPA cluster.
        !            94:     foreach my $port ($lond_port) {
        !            95:         print "Opening firewall access on port $port.\n";
        !            96:         my $result;
        !            97:         if ($port eq $lond_port) {
        !            98:             my (@port_error,@command_error,@lond_port_open);
        !            99:             my %iphost = &Apache::lonnet::get_iphost();
        !           100:             if (keys(%iphost) > 0) {
        !           101:                 &firewall_close_anywhere($port);
        !           102:                 foreach my $ip (keys(%iphost)) {
        !           103:                     my $firewall_command = 
        !           104:                         "$iptables -I $fw_chain -p tcp -s $ip -d 0/0 --dport $port -j ACCEPT";
        !           105:                     system($firewall_command);
        !           106:                     my $return_status = $?>>8;
        !           107:                     if ($return_status == 1) {
        !           108:                         push (@port_error,$ip);
        !           109:                     } elsif ($return_status == 2) {
        !           110:                         push(@command_error,$ip);
        !           111:                     } elsif ($return_status == 0) {
        !           112:                         push(@lond_port_open,$ip);
1.34      raeburn   113:                     }
                    114:                 }
                    115:             }
1.36    ! raeburn   116:             if (@lond_port_open) {
        !           117:                 push(@opened,$port);
        !           118:                 print "Port $port opened for ".scalar(@lond_port_open)." IP addresses\n";  
        !           119:             }
        !           120:             if (@port_error) {
        !           121:                 print "Error opening port $port for following IP addresses: ".join(', ',@port_error)."\n";
        !           122:             }
        !           123:             if (@command_error) {
        !           124:                 print "Bad command error opening port for following IP addresses: ".
        !           125:                       join(', ',@command_error)."\n".
        !           126:                       'Command was: "'."$iptables -I $fw_chain -p tcp -s ".'$ip'." -d 0/0 --dport $port -j ACCEPT".'", where $ip is IP address'."\n";
        !           127:             }
        !           128:         } else {
        !           129:             my $firewall_command =
1.34      raeburn   130:                 "$iptables -I $fw_chain -p tcp -d 0/0 --dport $port -j ACCEPT";
                    131:             system($firewall_command);
                    132:             my $return_status = $?>>8;
                    133:             if ($return_status == 1) {
                    134:                 # Error
                    135:                 print "Error opening port.\n";
                    136:             } elsif ($return_status == 2) {
                    137:                 # Bad command
                    138:                 print "Bad command error opening port.  Command was\n".
                    139:                       "  ".$firewall_command."\n";
                    140:             } elsif ($return_status == 0) {
                    141:                 push(@opened,$port);
                    142:             }
                    143:         }
                    144:     }
1.33      www       145:     foreach my $port ($lond_port) {
1.34      raeburn   146:         if (!grep(/^\Q$port\E$/,@opened)) {
                    147:             return 'Required port not open: '.$port."\n";  
1.22      matthew   148:         }
1.20      matthew   149:     }
1.34      raeburn   150:     return 'ok';
1.20      matthew   151: }
                    152: 
                    153: sub firewall_is_port_open {
1.34      raeburn   154:     my ($port) = @_;
1.36    ! raeburn   155:     # for lond port returns number of source IPs for which firewall port is open
        !           156:     # for other ports returns 1 if the firewall port is open, 0 if not.
1.20      matthew   157:     #
                    158:     # check if firewall is active or installed
                    159:     return if (! &firewall_is_active);
1.36    ! raeburn   160:     if ($port eq $lond_port) {
        !           161:         my %iphost = &Apache::lonnet::get_iphost();
        !           162:         foreach my $ip (keys(%iphost)) {
        !           163:             my $count = `$iptables -L -n 2>/dev/null | grep "tcp dpt:$port" | wc -l`;
        !           164:             return $count;
        !           165:         }
1.20      matthew   166:     } else {
1.36    ! raeburn   167:         if (`$iptables -L -n 2>/dev/null | grep "tcp dpt:$port"`) { 
        !           168:             return 1;
        !           169:         } else {
        !           170:             return 0;
        !           171:         }
1.20      matthew   172:     }
                    173: }
                    174: 
                    175: sub firewall_is_active {
                    176:     if (-e '/proc/net/ip_tables_names') {
                    177:         return 1;
                    178:     } else {
                    179:         return 0;
                    180:     }
                    181: }
                    182: 
                    183: sub firewall_close_port {
1.34      raeburn   184:     return 'inactive firewall' if (! &firewall_is_active);
                    185:     return 'port number unknown' if !$lond_port;
1.36    ! raeburn   186:     if (! `$iptables -L -n 2>/dev/null | grep $fw_chain | wc -l`) {
        !           187:         return 'Expected chain "'.$fw_chain.'" missing from iptables'."\n";
        !           188:     }
1.33      www       189:     foreach my $port ($lond_port) {
1.34      raeburn   190:         print "Closing firewall access on port $port\n";
1.36    ! raeburn   191:         if ($port eq $lond_port) {
        !           192:             my (@port_error,@command_error,@lond_port_close);
        !           193:             my %iphost = &Apache::lonnet::get_iphost();
        !           194:             my %toclose;
        !           195:             if (keys(%iphost) > 0) {
        !           196:                 open(PIPE, "$iptables -n -L $fw_chain |");
        !           197:                 while (<PIPE>) {
        !           198:                     chomp();
        !           199:                     next unless (/dpt:\Q$port\E\s*$/);
        !           200:                     if (/^ACCEPT\s+tcp\s+\-{2}\s+([\S]+)\s+/) {
        !           201:                         $toclose{$1} = $port;
        !           202:                     }
        !           203:                 }
        !           204:                 close(PIPE);
        !           205:             }
        !           206:             foreach my $ip (keys(%iphost)) {
        !           207:                 next unless (exists($toclose{$ip}));
        !           208:                 my $firewall_command =
        !           209:                     "$iptables -D $fw_chain -p tcp -s $ip -d 0/0 --dport $port -j ACCEPT";
        !           210:                 system($firewall_command);
        !           211:                 my $return_status = $?>>8;
        !           212:                 if ($return_status == 1) {
        !           213:                     push (@port_error,$ip);
        !           214:                 } elsif ($return_status == 2) {
        !           215:                     push(@command_error,$ip);
        !           216:                 } elsif ($return_status == 0) {
        !           217:                     push(@lond_port_close,$ip);
        !           218:                 }
        !           219:             }
        !           220:             if (@lond_port_close) {
        !           221:                 print "Port $port closed for ".scalar(@lond_port_close)." IP addresses\n";
        !           222:             }
        !           223:             if (@port_error) {
        !           224:                 print "Error closing port $port for following IP addresses: ".join(', ',@port_error)."\n";
        !           225:             }
        !           226:             if (@command_error) {
        !           227:                 print "Bad command error opening port for following IP addresses: ".
        !           228:                       join(', ',@command_error)."\n".
        !           229:                       'Command was: "'."$iptables -D $fw_chain -p tcp -s ".'$ip'." -d 0/0 --dport $port -j ACCEPT".'", where $ip is IP address'."\n";
        !           230:             }
        !           231:             &firewall_close_anywhere($port);
1.34      raeburn   232:         } else {
1.36    ! raeburn   233:             my $firewall_command = 
        !           234:                 "$iptables -D $fw_chain -p tcp -d 0/0 --dport $port -j ACCEPT";
        !           235:             system($firewall_command);
        !           236:             my $return_status = $?>>8;
        !           237:             if ($return_status == 1) {
        !           238:                 # Error
        !           239:                 print "Error closing port.\n";
        !           240:             } elsif ($return_status == 2) {
        !           241:                 # Bad command
        !           242:                 print "Bad command error closing port.  Command was\n".
        !           243:                       "  ".$firewall_command."\n";
        !           244:             } else {
        !           245:                 print "Port closed.\n";
        !           246:             }
1.22      matthew   247:         }
1.20      matthew   248:     }
1.34      raeburn   249:     return;
                    250: }
                    251: 
                    252: sub get_lond_port {
                    253:     my $perlvarref=&LONCAPA::Configuration::read_conf();
                    254:     my $lond_port;
                    255:     if (ref($perlvarref) eq 'HASH') {
                    256:         if (defined($perlvarref->{'londPort'})) {
                    257:             $lond_port = $perlvarref->{'londPort'};
                    258:         }
                    259:     }
                    260:     return $lond_port;
1.20      matthew   261: }
                    262: 
1.36    ! raeburn   263: sub firewall_close_anywhere {
        !           264:     my ($port) = @_;
        !           265:     open(PIPE, "$iptables --line-numbers -n -L $fw_chain |");
        !           266:     while (<PIPE>) {
        !           267:         next unless (/dpt:\Q$port\E/);
        !           268:         chomp();
        !           269:         if (/^(\d+)\s+ACCEPT\s+tcp\s+\-{2}\s+0\.0\.0\.0\/0\s+0\.0\.0\.0\/0/) {
        !           270:             my $firewall_command = "$iptables -D $fw_chain $1";
        !           271:             system($firewall_command);
        !           272:             my $return_status = $?>>8;
        !           273:             if ($return_status == 1) {
        !           274:                 print 'Error closing port '.$port.' for source "anywhere"'."\n";
        !           275:             } elsif ($return_status == 2) {
        !           276:                 print 'Bad command error closing port '.$port.' for source "anywhere".  Command was'."\n".
        !           277:                       ' '.$firewall_command."\n";
        !           278:             } else {
        !           279:                 print 'Port '.$port.' closed for source "anywhere"'."\n";
        !           280:             }
        !           281:         }
        !           282:     }
        !           283:     close(PIPE);
        !           284: }
        !           285: 
1.20      matthew   286: } # End firewall variable scope
                    287: 
1.11      albertel  288: sub stop_daemon {
1.19      albertel  289:     my ($daemon,$killallname)=@_;
1.11      albertel  290:     my $pidfile="/home/httpd/perl/logs/$daemon.pid";
                    291:     
1.24      albertel  292:     printf("%-15s ",$daemon);
1.11      albertel  293:     if (-e $pidfile) {
                    294: 	open(PIDFILE,$pidfile);
                    295: 	my $daemonpid=<PIDFILE>;
                    296: 	chomp($daemonpid);
                    297: 	kill TERM => $daemonpid;
1.32      albertel  298: 	my $count=0;
                    299: 	while ($count++ < 5 && kill(0 => $daemonpid)) {
                    300: 	    sleep 1;
                    301: 	}
1.11      albertel  302: 	if (kill 0 => $daemonpid) {
                    303: 	    kill KILL => $daemonpid;
1.26      albertel  304: 	    sleep 1;
1.11      albertel  305: 	    if (kill 0 => $daemonpid) {
1.19      albertel  306: 		print("failed to kill");
1.11      albertel  307: 	    } else {
1.19      albertel  308: 		print("killed");
1.11      albertel  309: 	    }
                    310: 	} else {
1.19      albertel  311: 	    print("stopped");
1.11      albertel  312: 	}
1.19      albertel  313:     } else {
                    314: 	print("not running");
                    315:     }
                    316:     system("killall -q -0 $killallname");
                    317:     if ($? == 0) {
                    318: 	system("killall -q $killallname");
                    319: 	print(", killed off extraneous processes");
1.11      albertel  320:     }
1.24      albertel  321:     unlink($pidfile);
1.19      albertel  322:     print("\n");
1.11      albertel  323: }
                    324: 
1.30      albertel  325: sub clean_sockets {
                    326:     opendir(SOCKETS,"/home/httpd/sockets/");
1.34      raeburn   327:     my $perlvarref=&LONCAPA::Configuration::read_conf();
                    328:     return if (ref($perlvarref) ne 'HASH');
1.30      albertel  329:     while (my $fname=readdir(SOCKETS)) {
                    330: 	next if (-d $fname
1.34      raeburn   331: 		 || $fname=~/(mysqlsock|maximasock|\Q$perlvarref->{'lonSockDir'}\E)/);
1.30      albertel  332: 	unlink("/home/httpd/sockets/$fname");
                    333:     }
                    334: }
1.20      matthew   335: 
1.29      albertel  336: if ($command eq "restart") {
1.12      albertel  337:     print 'Restarting LON-CAPA'."\n";
                    338:     print 'Ending LON-CAPA client and daemon processes'."\n";
1.35      raeburn   339:     foreach my $daemon ('lonsql','lond','lonc','lonmemcached','lonmaxima','lonr') {
1.19      albertel  340: 	my $killallname=$daemon;
                    341: 	if ($daemon eq 'lonc') { $killallname='loncnew'; }
                    342: 	&stop_daemon($daemon,$killallname);
1.12      albertel  343:     }
                    344:     print 'Starting LON-CAPA client and daemon processes (please be patient)'.
                    345: 	"\n";
1.18      albertel  346:     system("su www -c '/home/httpd/perl/loncron --justcheckdaemons'");
1.16      albertel  347: } elsif ($command eq "stop") {
1.6       harris41  348:     print 'Stopping LON-CAPA'."\n";
1.35      raeburn   349:     foreach my $daemon ('lonsql','lond','lonc','lonmemcached','lonmaxima','lonr') {
1.19      albertel  350: 	my $killallname=$daemon;
                    351: 	if ($daemon eq 'lonc') { $killallname='loncnew'; }
                    352: 	&stop_daemon($daemon,$killallname);
1.11      albertel  353:     }
1.34      raeburn   354:     my $firewall_result = &firewall_close_port();
                    355:     if ($firewall_result) {
                    356:         print "$firewall_result\n";
                    357:     }
1.30      albertel  358:     &clean_sockets();
1.16      albertel  359: } elsif ($command eq "start") {
1.34      raeburn   360:     my $firewall_result = &firewall_open_port();
                    361:     if (($firewall_result eq 'ok') || ($firewall_result eq 'inactive firewall')) {
                    362:         if ($firewall_result eq 'inactive firewall') {
                    363:             print "WARNING: iptables firewall is currently inactive\n";
                    364:         }
                    365:         print 'Starting LON-CAPA'."\n";
                    366:         print 'Starting LON-CAPA client and daemon processes (please be patient)'.
                    367: 	      "\n";
                    368:         system("su www -c '/home/httpd/perl/loncron --justcheckdaemons'");
                    369:     } else {
                    370:         print "Not starting LON-CAPA\n";
                    371:         if ($firewall_result eq 'port number unknown') {
                    372:             print "Could not check for status of LON-CAPA port in running firewall - port number unknown.  \n";
                    373:         } elsif ($firewall_result) {
                    374:             print "$firewall_result\n";
                    375:         }
                    376:     }
1.25      albertel  377: } elsif ($command eq "reload") {
                    378:     print 'Reload LON-CAPA config files'."\n";
                    379:     system("su www -c '/home/httpd/perl/loncron --justreload'");
1.16      albertel  380: } elsif ($command eq "status") {
1.34      raeburn   381:     my $lond_port = &get_lond_port();
                    382:     my $response=`/bin/cat /home/httpd/perl/logs/*.pid 2>&1`;
1.1       harris41  383:     if ($response=~/No such file or directory/) {
1.6       harris41  384: 	print 'LON-CAPA is not running.'."\n";
1.18      albertel  385:     } else {
1.6       harris41  386: 	print 'LON-CAPA is running.'."\n";
1.18      albertel  387: 	system("su www -c '/home/httpd/perl/loncron --justcheckconnections'");
1.1       harris41  388:     }
1.20      matthew   389:     if (! &firewall_is_active) {
                    390:         print 'The iptables firewall is not active'."\n";
                    391:     }
1.34      raeburn   392:     my $lond_port = &get_lond_port();
                    393:     if ($lond_port) {
                    394:         if (&firewall_is_port_open($lond_port)) {
                    395:             print "The LON-CAPA port ($lond_port) is open in firewall.\n";
                    396:         } elsif (&firewall_is_active) {
                    397:             print "The LON-CAPA port ($lond_port) is NOT open in running firewall!\n";
                    398:         }
                    399:     } else {
                    400:         if (&firewall_is_active) {
                    401:             print "Could not check for status of LON-CAPA port in running firewall - port number unknown.\n";
                    402:         } else {
                    403:             print "LON-CAPA port number is unknown, and firewall is not running.\n";
                    404:         }
1.20      matthew   405:     }
1.16      albertel  406: } else {
1.34      raeburn   407:     print "You need to specify one of restart|stop|start|status on the command line.\n";
1.1       harris41  408: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>