Annotation of loncom/lonManage, revision 1.16

1.1       foxr        1: #!/usr/bin/perl
                      2: # The LearningOnline Network with CAPA
                      3: #
                      4: #  lonManage supports remote management of nodes in a LonCAPA cluster.
                      5: #
1.16    ! foxr        6: #  $Id: lonManage,v 1.15 2003/09/16 09:49:54 foxr Exp $
1.1       foxr        7: #
1.16    ! foxr        8: # $Id: lonManage,v 1.15 2003/09/16 09:49:54 foxr Exp $
1.1       foxr        9: #
                     10: # Copyright Michigan State University Board of Trustees
                     11: #
                     12: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
                     13: ## LON-CAPA is free software; you can redistribute it and/or modify
                     14: # it under the terms of the GNU General Public License as published by
                     15: # the Free Software Foundation; either version 2 of the License, or
                     16: # (at your option) any later version.
                     17: #
                     18: # LON-CAPA is distributed in the hope that it will be useful,
                     19: # but WITHOUT ANY WARRANTY; without even the implied warranty of
                     20: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     21: # GNU General Public License for more details.
                     22: #
                     23: # You should have received a copy of the GNU General Public License
                     24: # along with LON-CAPA; if not, write to the Free Software
                     25: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                     26: #
                     27: # /home/httpd/html/adm/gpl.txt
                     28: #
                     29: # http://www.lon-capa.org/
                     30: #
                     31: #
                     32: #   lonManage supports management of remot nodes in a lonCAPA cluster.
                     33: #   it is a command line tool.  The following command line syntax (usage)
                     34: #   is supported:
                     35: #
1.16    ! foxr       36: #    lonManage  -push   <tablename>  newfile  [host]
1.1       foxr       37: #        Push <tablename> to the lonTabs directory.  Note that
                     38: #        <tablename> must be one of:
1.15      foxr       39: #           host  (hosts.tab)
1.1       foxr       40: #           domain (domain.tab)
                     41: #
1.16    ! foxr       42: #    lonManage  -reinit lonc [host]
1.1       foxr       43: #           Sends a HUP signal to the remote systems's lond.
                     44: #
1.16    ! foxr       45: #    lonmanage  -reinit lond [host]
1.1       foxr       46: #          Requests the remote system's lond perform the same action as if
                     47: #          it had received a HUP signal.
                     48: #
                     49: #    In the above syntax, the host above is the hosts.tab name of a host,
1.16    ! foxr       50: #    not the IP address of the host
        !            51: #  
        !            52: #   If [host] is not supplied, every host in the client's hosts.tab
        !            53: #   table is iterated through and procesed..
1.1       foxr       54: #
1.3       foxr       55: #  $Log: lonManage,v $
1.16    ! foxr       56: #  Revision 1.15  2003/09/16 09:49:54  foxr
        !            57: #  Adjust the usage message to reflect what actually will happen on
        !            58: #  --reinit={lond|lonc}
        !            59: #
1.15      foxr       60: #  Revision 1.14  2003/09/08 09:45:20  foxr
                     61: #  Remove BUGBUG about comment about authentication as we'll be doing
                     62: #  host based authentication initially (no need for lonManage to do anything),
                     63: #  and certificate based later (need at that time).
                     64: #
1.14      foxr       65: #  Revision 1.13  2003/08/19 10:26:24  foxr
                     66: #  Initial working version... tested against an unmodified lond this
                     67: #  produces an unknown_cmd response which is about what I'd expect.
                     68: #
1.13      foxr       69: #  Revision 1.12  2003/08/18 11:08:07  foxr
                     70: #  Debug request building in Transact.
                     71: #
1.12      foxr       72: #  Revision 1.11  2003/08/18 10:45:32  foxr
                     73: #  Felt strongly enough about hoisting ReadConfiguration into a separate sub
                     74: #  that I did it now before I forgot.
                     75: #
1.11      foxr       76: #  Revision 1.10  2003/08/18 10:43:31  foxr
                     77: #  Code/test ValidHost.  The hosts.tab and the perl variables are read in as
                     78: #  global hashes as a side effect.  May later want to clean this up by making
                     79: #  a separate getconfig function and hoisting the config reads into that.
                     80: #
1.10      foxr       81: #  Revision 1.9  2003/08/18 10:25:46  foxr
                     82: #  Write ReinitProcess function in terms of ValidHost and Transact.
                     83: #
1.9       foxr       84: #  Revision 1.8  2003/08/18 10:18:21  foxr
                     85: #  Completed PushFile function in terms of
                     86: #  - ValidHost - Determines if target host is valid.
                     87: #  - Transact  - Performs one of the valid transactions with the
                     88: #                appropriate lonc<-->lond client/server pairs.
                     89: #
1.8       foxr       90: #  Revision 1.7  2003/08/18 09:56:01  foxr
                     91: #  1. Require to be run as root.
                     92: #  2. Catch case where no operation switch is supplied and put out usage.
                     93: #  3. skeleton/comments for PushFile function.
                     94: #
1.7       foxr       95: #  Revision 1.6  2003/08/12 11:02:59  foxr
                     96: #  Implement command switch dispatching.
                     97: #
1.6       foxr       98: #  Revision 1.5  2003/08/12 10:55:42  foxr
                     99: #  Complete command line parsing (tested)
                    100: #
1.5       foxr      101: #  Revision 1.4  2003/08/12 10:40:44  foxr
                    102: #  Get switch parsing right.
                    103: #
1.4       foxr      104: #  Revision 1.3  2003/08/12 10:22:35  foxr
                    105: #  Put in parameter parsing infrastructure
                    106: #
1.3       foxr      107: #  Revision 1.2  2003/08/12 09:58:49  foxr
                    108: #  Add usage and skeleton documentation.
1.2       foxr      109: #
1.3       foxr      110: #
1.10      foxr      111: 
1.14      foxr      112: 
1.13      foxr      113: 
1.10      foxr      114: # Modules required:
                    115: 
1.7       foxr      116: use strict;			# Because it's good practice.
                    117: use English;			# Cause I like meaningful names.
1.3       foxr      118: use Getopt::Long;
1.10      foxr      119: use LONCAPA::Configuration;	# To handle configuration I/O.
1.13      foxr      120: use IO::Socket::UNIX;		# To communicate with lonc.
1.10      foxr      121: 
                    122: # File scoped variables:
                    123: 
                    124: my %perlvar;			# Perl variable defs from apache config.
                    125: my %hostshash;			# Host table as a host indexed hash.
1.2       foxr      126: 
1.13      foxr      127: #
                    128: #   prints out utility's command usage info.
                    129: #
1.3       foxr      130: sub Usage  {
1.2       foxr      131:     print "Usage:";
                    132:     print <<USAGE;
1.16    ! foxr      133:     lonManage  --push=<tablename>  newfile  [host]
1.2       foxr      134:         Push <tablename> to the lonTabs directory.  Note that
                    135:         <tablename> must be one of:
1.15      foxr      136:            host  (hosts.tab)
1.2       foxr      137:            domain (domain.tab)
                    138: 
1.16    ! foxr      139:     lonManage  --reinit=lonc [host]
1.15      foxr      140:        Causes lonc in the remote system to reread hosts.tab and
                    141:        adjust the set of clients that are being maintained to match
                    142:        the new file.
                    143:        
1.2       foxr      144: 
1.16    ! foxr      145:     lonManage  --reinit=lond [host]
1.15      foxr      146:        Causes lond in the remote system to reread the hosts.tab file
                    147:        and adjust the set of servers to match changes in that file.
1.2       foxr      148: 
                    149:     In the above syntax, the host above is the hosts.tab name of a host,
                    150:     not the IP address of the host.
1.16    ! foxr      151: 
        !           152:     If [host] is omitted, all hosts in the hosts.tab file are iterated
        !           153:     over.
        !           154: 
1.2       foxr      155: USAGE
                    156: 
                    157: 
                    158: }
1.13      foxr      159: #
                    160: #   Lifted from lonnet.pm - and we need to figure out a way to get it back in.
                    161: #   Performas a transaction with lond via the lonc proxy server.
                    162: #   Parameter:
                    163: #      cmd  - The text of the request.
                    164: #      host - The host to which the request ultimately goes.
                    165: #   Returns:
                    166: #      The text of the reply from the lond or con_lost if not able to contact
                    167: #      lond/lonc etc.
                    168: #
                    169: sub subreply {
                    170:     my ($cmd,$server)=@_;
                    171:     my $peerfile="$perlvar{'lonSockDir'}/$server";
                    172:     my $client=IO::Socket::UNIX->new(Peer    =>"$peerfile",
                    173:                                      Type    => SOCK_STREAM,
                    174:                                      Timeout => 10)
                    175:        or return "con_lost";
                    176:     print $client "$cmd\n";
                    177:     my $answer=<$client>;
                    178:     if (!$answer) { $answer="con_lost"; }
                    179:     chomp($answer);
                    180:     return $answer;
                    181: }
                    182: #   >>> BUGBUG <<< 
1.2       foxr      183: #
1.3       foxr      184: #  Use Getopt::Long to parse the parameters of the program.
                    185: #
                    186: #  Return value is a list consisting of:
                    187: #    A 'command' which is one of:
                    188: #       push   - table push requested.
                    189: #       reinit - reinit requested.
                    190: #   Additional parameters as follows:
                    191: #       for push: Tablename, hostname
                    192: #       for reinit: Appname  hostname
                    193: #
                    194: #   This function does not validation of the parameters of push and
                    195: #   reinit.
1.4       foxr      196: #
                    197: #   returns a list.  The first element of the list is the operation name
                    198: #   (e.g. reinit or push).  The second element is the switch parameter.
                    199: #   for push, this is the table name, for reinit, this is the process name.
                    200: #   Additional elements of the list are the command argument.  The count of
                    201: #   command arguments is validated, but not their semantics.
                    202: #
1.3       foxr      203: #   returns an empty list if the parse fails.
                    204: #
                    205: 
                    206: sub ParseArgs {
1.4       foxr      207:     my $pushing   = '';
1.7       foxr      208:     my $reinitting = '';
1.5       foxr      209: 
1.4       foxr      210:     if(!GetOptions('push=s'    => \$pushing,
                    211: 	           'reinit=s'  => \$reinitting)) {
                    212: 	return ();
                    213:     }
                    214: 
                    215:     #  Require exactly   one of --push and --reinit
                    216: 
1.5       foxr      217:     my $command    = '';
1.4       foxr      218:     my $commandarg = '';
1.5       foxr      219:     my $paramcount = @ARGV; 	# Number of additional arguments.
                    220:     
                    221: 
1.4       foxr      222:     if($pushing ne '') {
1.5       foxr      223: 
1.16    ! foxr      224:         # --push takes in addition a table, and an optional  host:
1.5       foxr      225:         #
1.16    ! foxr      226: 	if(($paramcount != 2) && ($paramcount != 1)) {
1.5       foxr      227: 	    return ();		# Invalid parameter count.
                    228: 	}
1.4       foxr      229: 	if($command ne '') {
                    230: 	    return ();
                    231: 	} else {
1.5       foxr      232: 	    
1.4       foxr      233: 	    $command    = 'push';
                    234: 	    $commandarg = $pushing;
                    235: 	}
                    236:     }
1.5       foxr      237: 
1.4       foxr      238:     if ($reinitting ne '') {
1.5       foxr      239: 
1.16    ! foxr      240: 	# --reinit takes in addition just an optional  host name
1.5       foxr      241: 
1.16    ! foxr      242: 	if($paramcount > 1) {
1.5       foxr      243: 	    return ();
                    244: 	}
1.4       foxr      245: 	if($command ne '') {
                    246: 	    return ();
                    247: 	} else {
                    248: 	    $command    = 'reinit';
                    249: 	    $commandarg = $reinitting; 
                    250: 	}
                    251:     }
                    252: 
1.5       foxr      253:     #  Build the result list:
                    254: 
                    255:     my @result = ($command, $commandarg);
                    256:     my $i;
                    257:     for($i = 0; $i < $paramcount; $i++) {
                    258: 	push(@result, $ARGV[$i]);
                    259:     }
                    260:     
                    261:     return @result;
1.3       foxr      262: }
1.10      foxr      263: #
1.11      foxr      264: #  Read the loncapa configuration stuff.
                    265: #
                    266: sub ReadConfig {
                    267:     my $perlvarref = LONCAPA::Configuration::read_conf('loncapa.conf');
                    268:     %perlvar       = %{$perlvarref};
                    269:     my $hoststab   = LONCAPA::Configuration::read_hosts(
                    270: 					"$perlvar{'lonTabDir'}/hosts.tab");
                    271:     %hostshash     = %{$hoststab};
                    272: 
                    273: }
                    274: #
1.10      foxr      275: #  Determine if the target host is valid.
                    276: #  This is done by reading the current hosts.tab file.
                    277: #  For the host to be valid, it must be inthe file.
                    278: #
                    279: #  Parameters:
                    280: #     host   - Name of host to check on.
                    281: #  Returns:
                    282: #     true   if host is valid.
                    283: #     false  if host is invalid.
                    284: #
1.8       foxr      285: sub ValidHost {
1.10      foxr      286:     my $host       = shift;
1.11      foxr      287:    
1.10      foxr      288: 
                    289:     return defined $hostshash{$host};
                    290: 
1.8       foxr      291: }
1.13      foxr      292: 
                    293: 
                    294: 
1.12      foxr      295: #
                    296: #  Performs a transaction with lonc.
                    297: #  By the time this is called, the transaction has already been
                    298: #  validated by the caller.
                    299: #
                    300: #   Parameters:
                    301: #
                    302: #   host    - hosts.tab name of the host whose lonc we'll be talking to.
                    303: #   command - The base command we'll be asking lond to execute.
                    304: #   body    - [optional] If supplied, this is a command body that is a ref.
                    305: #             to an array of lines that will be appended to the 
                    306: #             command.
                    307: #
                    308: #  NOTE:
                    309: #    The command will be done as an encrypted operation.
                    310: #
1.8       foxr      311: sub Transact {
1.12      foxr      312:     my $host    = shift;
                    313:     my $command = shift;
                    314:     my $haveBody= 0;
                    315:     my $body;
                    316:     my $i;
                    317: 
                    318:     if(scalar @ARG) {
                    319: 	$body = shift;
                    320: 	$haveBody = 1;
                    321:     }
                    322:     #  Construct the command to send to the server:
                    323:     
                    324:     my $request = "encrypt\:";	# All requests are encrypted.
                    325:     $request   .= $command;
                    326:     if($haveBody) {
                    327: 	$request .= "\:";
                    328: 	my $bodylines = scalar @$body;
                    329: 	for($i = 0; $i < $bodylines; $i++) {
                    330: 	    $request .= $$body[$i];
                    331: 	}
                    332:     } else {
                    333: 	$request .= "\n";
                    334:     }
1.13      foxr      335:     # Body is now built... transact with lond..
                    336:     
                    337:     my $answer = subreply($request, $host);
                    338: 
                    339:     print "$answer\n";
1.10      foxr      340: 
1.8       foxr      341: }
1.7       foxr      342: #
                    343: #   Called to push a file to the remote system.
                    344: #   The only legal files to push are hosts.tab and domain.tab.
                    345: #   Security is somewhat improved by
                    346: #   
                    347: #   - Requiring the user run as root.
                    348: #   - Connecting with lonc rather than lond directly ensuring this is a loncapa
                    349: #     host
                    350: #   - We must appear in the remote host's hosts.tab file.
                    351: #   - The host must appear in our hosts.tab file.
                    352: #
                    353: #  Parameters:
                    354: #     tablename - must be one of hosts or domain.
                    355: #     tablefile - name of the file containing the table to push.
                    356: #     host      - name of the host to push this file to.     
                    357: #
1.13      foxr      358: #    >>>BUGBUG<<< This belongs in lonnet.pm.
                    359: #
1.7       foxr      360: sub PushFile {
                    361:     my $tablename = shift;
                    362:     my $tablefile = shift;
                    363:     my $host      = shift;
                    364:     
1.8       foxr      365:     # Open the table file:
                    366: 
                    367:     if(!open(TABLEFILE, "<$tablefile")) {
                    368: 	die "ENOENT - No such file or directory $tablefile";
                    369:     }
                    370:   
                    371:     # Require that the host be valid:
                    372: 
                    373:     if(!ValidHost($host)) {
                    374: 	die "EHOSTINVAL - Invalid host $host"; # Ok so I invented this 'errno'.
                    375:     }
                    376:     # Read in the file.  If the table name is valid, push it.
                    377: 
                    378:     my @table = <TABLEFILE>;	#  These files are pretty small.
                    379:     close TABLEFILE;
                    380: 
                    381:     if( ($tablename eq "host")    ||
                    382: 	($tablename eq "domain")) {
1.16    ! foxr      383: 	print("Pushing $tablename to $host\n");
1.12      foxr      384: 	Transact($host, "pushfile:$tablename",\@table);
1.8       foxr      385:     } else {
                    386: 	die "EINVAL - Invalid parameter. tablename: $tablename must be host or domain";
                    387:     }
1.7       foxr      388: }
1.9       foxr      389: #
                    390: #   This function is called to reinitialize a server in a remote host.
                    391: #   The servers that can be reinitialized are:
                    392: #   - lonc   - The lonc client process.
                    393: #   - lond   - The lond daemon.
                    394: #  NOTE:
                    395: #    Reinitialization in this case means re-scanning the hosts table,
                    396: #    starting new lond/lonc's as approprate and stopping existing lonc/lond's.
                    397: #
                    398: #  Parameters:
                    399: #     process - The name of the process to reinit (lonc or lond).
                    400: #     host    - The host in which this reinit will happen.
                    401: #
1.13      foxr      402: #   >>>BUGBUG<<<< This belongs  in lonnet.pm
                    403: #
1.9       foxr      404: sub ReinitProcess {
                    405:     my $process = shift;
                    406:     my $host    = shift;
1.3       foxr      407: 
1.9       foxr      408:     #  Ensure the host is valid:
                    409:     
                    410:     if(!ValidHost($host)) {
                    411: 	die "EHOSTINVAL - Invalid host $host";
                    412:     }
                    413:     # Ensure target process selector is valid:
                    414: 
                    415:     if(($process eq "lonc") ||
                    416:        ($process eq "lond")) {
1.16    ! foxr      417: 	print("Reinitializing $process in $host\n");
1.9       foxr      418: 	Transact($host, "reinit:$process");
                    419:     } else {
                    420: 	die "EINVAL -Invalid parameter. Process $process must be lonc or lond";
                    421:     }
1.7       foxr      422: }
1.6       foxr      423: #--------------------------- Entry point: --------------------------
                    424: 
1.16    ! foxr      425: ReadConfig;			# Read the configuration info (incl.hosts).
        !           426: 
        !           427: 
1.6       foxr      428: #  Parse the parameters
                    429: #  If command parsing failed, then print usage:
1.2       foxr      430: 
1.7       foxr      431: my @params   = ParseArgs;
                    432: my $nparam   = @params;
1.3       foxr      433: 
                    434: if($nparam == 0) {
1.2       foxr      435:     Usage;
1.4       foxr      436:     exit -1;
1.2       foxr      437: }
1.7       foxr      438: #
                    439: #   Next, ensure we are running as EID root.
                    440: #
                    441: if ($EUID != 0) {
                    442:     die "ENOPRIV - No privilege for requested operation"
1.6       foxr      443: }
                    444: 
1.4       foxr      445: 
1.6       foxr      446: #   Based on the operation requested invoke the appropriate function:
                    447: 
1.7       foxr      448: my $operation = shift @params;
1.6       foxr      449: 
                    450: if($operation eq "push") {  # push tablename filename host
1.7       foxr      451:     my $tablename = shift @params;
                    452:     my $tablefile = shift @params;
                    453:     my $host      = shift @params;
1.16    ! foxr      454:     if($host) {
        !           455: 	PushFile($tablename, $tablefile, $host);
        !           456:     } else {			# Push to whole cluster.
        !           457: 	foreach my $host (keys %hostshash) {
        !           458: 	    PushFile($tablename, $tablefile, $host);
        !           459: 	}
        !           460:     }
1.6       foxr      461: 
1.7       foxr      462: } elsif($operation eq "reinit") {	# reinit processname host.
                    463:     my $process   = shift @params;
                    464:     my $host      = shift @params;
1.16    ! foxr      465:     if ($host) {
        !           466: 	ReinitProcess($process, $host);
        !           467:     } else {			# Reinit whole cluster.
        !           468: 	foreach my $host (keys %hostshash) {
        !           469: 	    ReinitProcess($process,$host);
        !           470: 	}
        !           471:     }
        !           472: } 
1.7       foxr      473: else {
                    474:     Usage;
1.6       foxr      475: }
1.4       foxr      476: exit 0;
1.2       foxr      477: 
                    478: =head1 NAME
                    479:     lonManage - Command line utility for remote management of lonCAPA
                    480:     cluster nodes.
                    481: 
                    482: =head1 SYNOPSIS
                    483: 
                    484: Usage:
1.3       foxr      485:     B<lonManage  --push=<tablename>  newfile  host>
1.2       foxr      486:         Push <tablename> to the lonTabs directory.  Note that
                    487:         <tablename> must be one of:
                    488:            hosts  (hosts.tab)
                    489:            domain (domain.tab)
                    490: 
1.3       foxr      491:     B<lonManage  --reinit=lonc host>
1.2       foxr      492:            Sends a HUP signal to the remote systems's lond.
                    493: 
1.3       foxr      494:     B<lonmanage  --reinit=lond host>
1.2       foxr      495:           Requests the remote system's lond perform the same action as if
                    496:           it had received a HUP signal.
                    497: 
                    498:     In the above syntax, the host above is the hosts.tab name of a host,
                    499:     not the IP address of the host.
                    500: 
                    501: 
                    502: =head1 DESCRIPTION
                    503: 
                    504: =head1 PREREQUISITES
1.3       foxr      505: 
1.7       foxr      506: =item strict
1.3       foxr      507: =item Getopt::Long
1.7       foxr      508: =item English
1.13      foxr      509: =item IO::Socket::UNIX
                    510: 
                    511: =head1 KEY Subroutines.
1.2       foxr      512: 
                    513: =head1  CATEGORIES
                    514:     Command line utility
                    515: 
                    516: =cut

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.