Annotation of loncom/lonManage, revision 1.26

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.26    ! foxr        6: #  $Id: lonManage,v 1.25 2003/11/04 11:52:06 foxr Exp $
1.1       foxr        7: #
1.26    ! foxr        8: # $Id: lonManage,v 1.25 2003/11/04 11:52:06 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: #
1.10      foxr       56: 
1.14      foxr       57: 
1.13      foxr       58: 
1.10      foxr       59: # Modules required:
                     60: 
1.17      foxr       61: use lib ".";
                     62: 
1.7       foxr       63: use strict;			# Because it's good practice.
                     64: use English;			# Cause I like meaningful names.
1.3       foxr       65: use Getopt::Long;
1.17      foxr       66: use LondConnection;
1.23      foxr       67: use IO::Poll qw(POLLRDNORM POLLWRNORM POLLIN POLLHUP POLLOUT);
1.10      foxr       68: 
                     69: # File scoped variables:
                     70: 
                     71: my %perlvar;			# Perl variable defs from apache config.
                     72: my %hostshash;			# Host table as a host indexed hash.
1.2       foxr       73: 
1.19      foxr       74: my $MyHost="";			# Host name to use as me.
                     75: my $ForeignHostTab="";		# Name of foreign hosts table.
1.23      foxr       76: 
                     77: my $DefaultServerPort =  5663;	# Default server port if standalone.
1.21      foxr       78: my $ServerPort;			# Port used to connect to lond.
1.18      foxr       79: 
1.23      foxr       80: my $TransitionTimeout = 5;	# Poll timeout in seconds.
                     81: 
                     82: 
1.24      foxr       83: # LondConnection::SetDebug(10);
1.23      foxr       84: 
                     85: 
1.13      foxr       86: #
                     87: #   prints out utility's command usage info.
                     88: #
1.3       foxr       89: sub Usage  {
1.2       foxr       90:     print "Usage:";
                     91:     print <<USAGE;
1.18      foxr       92:  lonManage  [--myname=host --hosts=table] --push=<tablename>  newfile  [host]
1.2       foxr       93:         Push <tablename> to the lonTabs directory.  Note that
                     94:         <tablename> must be one of:
1.15      foxr       95:            host  (hosts.tab)
1.2       foxr       96:            domain (domain.tab)
                     97: 
1.18      foxr       98:  lonManage [--myname=host --hosts=table] --reinit=lonc [host]
1.15      foxr       99:        Causes lonc in the remote system to reread hosts.tab and
                    100:        adjust the set of clients that are being maintained to match
                    101:        the new file.
                    102:        
1.2       foxr      103: 
1.18      foxr      104:  lonManage [--myname=host --hosts=table] --reinit=lond [host]
1.15      foxr      105:        Causes lond in the remote system to reread the hosts.tab file
                    106:        and adjust the set of servers to match changes in that file.
1.2       foxr      107: 
                    108:     In the above syntax, the host above is the hosts.tab name of a host,
                    109:     not the IP address of the host.
1.16      foxr      110: 
                    111:     If [host] is omitted, all hosts in the hosts.tab file are iterated
                    112:     over.
                    113: 
1.26    ! foxr      114: lonManage [--myname=host --hosts=table] --edit=<tablename> editscript [host]
        !           115:      Requests lond edit the hosts or domain table (selected by
        !           116:      tablename) with the editing command in editscript.  If
        !           117:      host is supplied the individual host is operated on,
        !           118:      otherwise, the entire cluster is operated on.
        !           119:      The edit file has edit request, one per line of the form:
        !           120:      append|newline
        !           121:      replace|key|newline
        !           122:      delete|key
        !           123:      The key is a loncapa hostname if editing the host file
        !           124:      or a domain name if editing the domain table file.
        !           125: 
1.18      foxr      126:  For all of the above syntaxes if --myname=host and --hosts=table are
                    127:  supplied (both must be present), the utility runs in standalone mode
                    128:  presenting itself to the world as 'host' and using the hosts.tab file
                    129:  specified in the --hosts switch.
1.2       foxr      130: USAGE
                    131: 
                    132: 
                    133: }
1.21      foxr      134: 
1.23      foxr      135: #
                    136: #  Make a direct connection to the lond in 'host'.  The port is 
                    137: #  gotten from the global variable:  ServerPort.
                    138: #  Returns:
                    139: #    The connection or undef if one could not be formed.
                    140: #
1.21      foxr      141: sub MakeLondConnection {
                    142:     my $host = shift;
1.22      foxr      143: 
                    144:     my $Connection = LondConnection->new($host, $ServerPort);
                    145:     return return $Connection;
1.21      foxr      146: }
1.23      foxr      147: #
1.25      foxr      148: #   Process the connection state machine until the connection
                    149: #   becomes idle. This is used both to negotiate the initial
                    150: #   connection, during which the LondConnection sequences a rather 
                    151: #   complex state machine and during the transaction itself
                    152: #   for a simpler set of transitions.
                    153: #   All we really need to be concerned with is whether or not
                    154: #   we're readable or writable and the final state:
                    155: #
                    156: #   Parameter:
                    157: #       connection   - Represents the LondConnection to be sequenced.
                    158: #       timeout      - Maximum time to wait for readable/writable sockets.
                    159: #                      in seconds. < 0 waits forever.
                    160: #   Return:
                    161: #       'ok'         - We got to idle ok.
                    162: #       'error:msg'  - An error occured. msg describes the error.
                    163: #
                    164: sub SequenceStateMachine {
                    165:     my $connection   = shift;
                    166:     my $timeout      = shift;
                    167: 
                    168:     my $Socket       = $connection->GetSocket;
                    169:     my $returnstatus = "ok";	              # optimist!!!
                    170:     my $error        = 0;	              # Used to force early loop termination
                    171:                                               # damned perl has no break!!.
                    172:     my $state        = $connection->GetState;
                    173: 
                    174:     while(($connection->GetState ne "Idle") && (!$error)) {
1.26    ! foxr      175:       #
        !           176:       # Figure out what the connection wants. read/write and wait for it
        !           177:       # or for the timeout.
        !           178:       #
1.25      foxr      179: 	my $wantread = $connection->WantReadable;
                    180: 	my $poll     = new IO::Poll;
                    181: 	$poll->mask($Socket, => $wantread ? POLLIN : POLLOUT);
1.26    ! foxr      182: 	my $handlecount = $poll->poll($timeout);
        !           183: 	if($handlecount == 0) {            # no handles ready... timeout!!
1.25      foxr      184: 	    $returnstatus  = "error:";
                    185: 	    $returnstatus .= "Timeout in state $state\n";
                    186: 	    $error         = 1;
                    187: 	} else {
1.26    ! foxr      188: 	    my $done     = $poll->handles();
1.25      foxr      189: 	    my $status;
                    190: 	    $status        = $wantread ? $connection->Readable :
1.26    ! foxr      191: 		$connection->Writable;
1.25      foxr      192: 	    if($status != 0) {
                    193: 		$returnstatus  =  "error:";
                    194: 		$returnstatus .=  " I/O failed in state $state\n";
                    195: 		$error = 1;
                    196: 	    }
                    197: 	}
                    198: 	$state = $connection->GetState;
                    199:     }
                    200:     return $returnstatus;
                    201: }
                    202: 
                    203: #
1.23      foxr      204: #    This function runs through the section of the connection
                    205: #   state machine that has to do with negotiating the startup 
                    206: #   sequence with lond.  The general strategy is to loop
                    207: #   until the connection state becomes idle or disconnected.
                    208: #   Disconnected indicates an error or rejection of the
                    209: #   connection at some point in the negotiation.
                    210: #   idle indicates a connection ready for a request.
                    211: #   The main loop consults the object to determine if it
                    212: #   wants to be writeable or readable, waits for that
                    213: #   condition on the socket (with timeout) and  then issues
                    214: #   the appropriate LondConnection call. Note that
                    215: #   LondConnection is capable of doing everything necessary
                    216: #   to get to the initial idle state.
                    217: # 
                    218: #
                    219: #  Parameters:
                    220: #     connection - A connection that has been created with
                    221: #                  the remote lond.  This connection should
                    222: #                  be in the Connected state ready to send
                    223: #                  the init sequence.
                    224: #
1.21      foxr      225: sub NegotiateStartup {
                    226:     my $connection = shift;
1.23      foxr      227:     my $returnstatus = "ok";	# Optimistic!!.
                    228: 
                    229:     my $state      = $connection->GetState;
1.26    ! foxr      230:    if($state ne "Connected") {
        !           231:       print "Error: Initial lond connection state: $state should be Connected\n";
        !           232:       return "error";
        !           233:    }
1.23      foxr      234: 
1.26    ! foxr      235:    return SequenceStateMachine($connection, $TransitionTimeout);
1.21      foxr      236: }
1.24      foxr      237: #
                    238: #   Perform a transaction with the remote lond.
                    239: #   Paramters:
                    240: #      connection - the connection object that represents
                    241: #                   a LondConnection to the remote lond.
                    242: #      command    - The request to send to the remote system.
                    243: #   Returns:
                    244: #       The 'reaction' of the lond to this command.
                    245: #       However if the connection to lond is lost during the transaction
                    246: #       or some other error occurs, the text "error:con_lost" is returned.
                    247: #    
1.21      foxr      248: sub PerformTransaction {
                    249:     my $connection  = shift;
                    250:     my $command     = shift;
1.24      foxr      251:     my $retval;                          # What we'll returnl.
1.25      foxr      252: 
1.24      foxr      253:    
                    254:     #  Set up the connection to do the transaction then
                    255:     #  do the I/O until idle or error.
                    256:     #
                    257:     $connection->InitiateTransaction($command);
                    258: 
1.25      foxr      259:     my $status = SequenceStateMachine($connection, $TransitionTimeout);
1.26    ! foxr      260:    if($status eq "ok") {
        !           261:       $retval = $connection->GetReply;
        !           262:    } else {
        !           263:       $retval = $status;
        !           264:    }
1.21      foxr      265: 
1.24      foxr      266:     return $retval;
1.21      foxr      267: }
1.13      foxr      268: #
1.21      foxr      269: # Performs a transaction direct to a remote lond.
1.13      foxr      270: #   Parameter:
                    271: #      cmd  - The text of the request.
                    272: #      host - The host to which the request ultimately goes.
                    273: #   Returns:
                    274: #      The text of the reply from the lond or con_lost if not able to contact
                    275: #      lond/lonc etc.
                    276: #
                    277: sub subreply {
1.21      foxr      278:     my $cmd = shift;
                    279:     my $host = shift;
                    280: 
                    281: 
1.26    ! foxr      282:    my $connection  = MakeLondConnection($host);
        !           283:    if ($connection eq undef) {
        !           284:       return "Connect Failed";
        !           285:    }
        !           286:    my $reply = NegotiateStartup($connection);
        !           287:    if($reply ne "ok") {
        !           288:       return "connection negotiation failed";
        !           289:    }
        !           290:    my $reply =  PerformTransaction($connection, $cmd);
        !           291:    return $reply;
1.21      foxr      292: 
                    293: 
1.13      foxr      294: }
1.2       foxr      295: #
1.3       foxr      296: #  Use Getopt::Long to parse the parameters of the program.
                    297: #
                    298: #  Return value is a list consisting of:
                    299: #    A 'command' which is one of:
                    300: #       push   - table push requested.
                    301: #       reinit - reinit requested.
                    302: #   Additional parameters as follows:
                    303: #       for push: Tablename, hostname
                    304: #       for reinit: Appname  hostname
                    305: #
                    306: #   This function does not validation of the parameters of push and
                    307: #   reinit.
1.4       foxr      308: #
                    309: #   returns a list.  The first element of the list is the operation name
                    310: #   (e.g. reinit or push).  The second element is the switch parameter.
                    311: #   for push, this is the table name, for reinit, this is the process name.
                    312: #   Additional elements of the list are the command argument.  The count of
                    313: #   command arguments is validated, but not their semantics.
                    314: #
1.3       foxr      315: #   returns an empty list if the parse fails.
                    316: #
                    317: 
1.18      foxr      318: 
1.3       foxr      319: sub ParseArgs {
1.26    ! foxr      320:     my $pushing    = '';
1.7       foxr      321:     my $reinitting = '';
1.26    ! foxr      322:     my $editing    = '';
        !           323:     
1.4       foxr      324:     if(!GetOptions('push=s'    => \$pushing,
1.26    ! foxr      325:                    'reinit=s'  => \$reinitting,
        !           326:                    'edit=s'    => \$editing,
        !           327: 		             'myname=s'  => \$MyHost,
        !           328: 		             'hosts=s'   => \$ForeignHostTab)) {
        !           329:       return ();
        !           330:    }
1.18      foxr      331:     #  The --myname and --hosts switch must have values and
                    332:     #  most both appear if either appears:
                    333: 
1.26    ! foxr      334:    if(($MyHost ne "") && ($ForeignHostTab eq "")) {
        !           335:       return ();
        !           336:    }
        !           337:    if(($ForeignHostTab ne "") && ($MyHost eq "")) {
        !           338:       return ();
        !           339:    }
        !           340: 
        !           341:     #  Require exactly   one of --push, --reinit, or --edit
        !           342: 
        !           343:    my $command    = '';
        !           344:    my $commandarg = '';
        !           345:    my $paramcount = @ARGV; 	# Number of additional arguments.
        !           346: 
        !           347:    my $commands = 0;           # Number of commands seen.
        !           348: 
        !           349:    if($pushing ne '') {
        !           350: 
        !           351:       # --push takes in addition a table, and an optional  host:
        !           352:       #
        !           353:         
        !           354: 	   if(($paramcount != 2) && ($paramcount != 1)) {
        !           355:          return ();		# Invalid parameter count.
        !           356:       }
1.5       foxr      357: 	    
1.26    ! foxr      358:       $commands++;              # Count a command seen.
        !           359:       $command    = 'push';
        !           360:       $commandarg = $pushing;
1.4       foxr      361: 	}
1.5       foxr      362: 
1.26    ! foxr      363:    if ($reinitting ne '') {
1.5       foxr      364: 
1.16      foxr      365: 	# --reinit takes in addition just an optional  host name
1.5       foxr      366: 
1.26    ! foxr      367:       if($paramcount > 1) {
        !           368:          return ();
        !           369:       }
        !           370:       $commands++;              #  Count a command seen.
        !           371:       $command    = 'reinit';
        !           372:       $commandarg = $reinitting; 
1.5       foxr      373: 	}
1.26    ! foxr      374: 
        !           375:    # --edit takes a script file and optional host name.
        !           376:    #
        !           377:    if ($editing ne "") {
        !           378:       if(($paramcount != 2) && ($paramcount != 1)) {
        !           379:          return ();              # Invalid parameter count.
        !           380:       }
        !           381:       
        !           382:       $commands++;               # Count a command seen.
        !           383:       $command    = 'edit';
        !           384:       $commandarg = $editing;
        !           385:    }
        !           386:    
        !           387:    #  At this point, $commands must be 1 or else we've seen
        !           388:    #  The wrong number of command switches:
        !           389:    
        !           390:    if($commands != 1) {
        !           391:       return ();
        !           392:    }
1.4       foxr      393: 
1.5       foxr      394:     #  Build the result list:
                    395: 
1.26    ! foxr      396:    my @result = ($command, $commandarg);
        !           397:    my $i;
        !           398:    for($i = 0; $i < $paramcount; $i++) {
        !           399:       push(@result, $ARGV[$i]);
        !           400:    }
1.5       foxr      401:     
                    402:     return @result;
1.3       foxr      403: }
1.10      foxr      404: #
1.26    ! foxr      405: #  Build the editor script.  This function:
        !           406: #  - Opens the edit script file.
        !           407: #  - Reads each line of the edit script file
        !           408: #  - Replaces the ending \n with a /
        !           409: #  - Appends it to the EditScript variable.
        !           410: #  - Returns the contents of the EditScript variable.
        !           411: #  Parameters:
        !           412: #     tabletype   - The type of table being built:
        !           413: #                   hosts or domain
        !           414: #     scriptname  - The script input file.
        !           415: #
        !           416: sub BuildEditScript {
        !           417:    my $TableType    = shift;
        !           418:    my $ScriptName   = shift;
        !           419:    
        !           420:    #Stub
        !           421:    
        !           422:    my @EditScript = (
        !           423:       "$TableType\:append|".
        !           424:          "nscll2\:nscl\:library\:lonkashy.nscl.msu.edu\:35.8.32.89"
        !           425:       );
        !           426:    return \@EditScript;
        !           427: }
1.19      foxr      428: #  Read the loncapa configuration stuff.  If ForeignHostTab is empty,
                    429: #  assume we are part of a loncapa cluster and read the hosts.tab
                    430: #  file from the config directory.  Otherwise, ForeignHossTab
                    431: #  is the name of an alternate configuration file to read in 
                    432: #  standalone mode.
1.11      foxr      433: #
                    434: sub ReadConfig {
1.19      foxr      435: 
1.26    ! foxr      436: 
        !           437:    
        !           438:    if($ForeignHostTab eq "") {
        !           439:        my $perlvarref = LondConnection::read_conf('loncapa.conf');
        !           440:        %perlvar    = %{$perlvarref};
        !           441:        my $hoststab   = LondConnection::read_hosts(
        !           442: 						   "$perlvar{lonTabDir}/hosts.tab");
        !           443:       %hostshash     = %{$hoststab};
        !           444:       $MyHost        = $perlvar{lonHostID}; # Set hostname from vars.
        !           445:       $ServerPort    = $perlvar{londPort};
        !           446:    } else {
1.23      foxr      447: 	
1.26    ! foxr      448:       LondConnection::ReadForeignConfig($MyHost, 
        !           449:                                         $ForeignHostTab);
        !           450:       my $hoststab = LondConnection::read_hosts($ForeignHostTab); #  we need to know too.
        !           451: 	   %hostshash   = %{$hoststab};
        !           452: 	   $ServerPort    = $DefaultServerPort;
        !           453:    }
1.11      foxr      454: }
                    455: #
1.10      foxr      456: #  Determine if the target host is valid.
                    457: #  This is done by reading the current hosts.tab file.
                    458: #  For the host to be valid, it must be inthe file.
                    459: #
                    460: #  Parameters:
                    461: #     host   - Name of host to check on.
                    462: #  Returns:
                    463: #     true   if host is valid.
                    464: #     false  if host is invalid.
                    465: #
1.8       foxr      466: sub ValidHost {
1.10      foxr      467:     my $host       = shift;
1.11      foxr      468:    
1.10      foxr      469: 
                    470:     return defined $hostshash{$host};
                    471: 
1.8       foxr      472: }
1.13      foxr      473: 
                    474: 
                    475: 
1.12      foxr      476: #
                    477: #  Performs a transaction with lonc.
                    478: #  By the time this is called, the transaction has already been
                    479: #  validated by the caller.
                    480: #
                    481: #   Parameters:
                    482: #
                    483: #   host    - hosts.tab name of the host whose lonc we'll be talking to.
                    484: #   command - The base command we'll be asking lond to execute.
                    485: #   body    - [optional] If supplied, this is a command body that is a ref.
                    486: #             to an array of lines that will be appended to the 
                    487: #             command.
                    488: #
                    489: #  NOTE:
                    490: #    The command will be done as an encrypted operation.
                    491: #
1.8       foxr      492: sub Transact {
1.12      foxr      493:     my $host    = shift;
                    494:     my $command = shift;
                    495:     my $haveBody= 0;
                    496:     my $body;
                    497:     my $i;
                    498: 
1.26    ! foxr      499:    if(scalar @ARG) {
        !           500:       $body = shift;
        !           501:       $haveBody = 1;
        !           502:    }
1.12      foxr      503:     #  Construct the command to send to the server:
                    504:     
1.26    ! foxr      505:    my $request = "encrypt\:";	# All requests are encrypted.
        !           506:    $request   .= $command;
        !           507:    if($haveBody) {
        !           508:       $request .= "\:";
        !           509:       my $bodylines = scalar @$body;
        !           510:       for($i = 0; $i < $bodylines; $i++) {
        !           511:          $request .= $$body[$i];
        !           512:       }
        !           513:    } else {
        !           514:       $request .= "\n";
        !           515:    }
1.13      foxr      516:     # Body is now built... transact with lond..
                    517:     
                    518:     my $answer = subreply($request, $host);
                    519: 
                    520:     print "$answer\n";
1.10      foxr      521: 
1.8       foxr      522: }
1.7       foxr      523: #
                    524: #   Called to push a file to the remote system.
                    525: #   The only legal files to push are hosts.tab and domain.tab.
                    526: #   Security is somewhat improved by
                    527: #   
                    528: #   - Requiring the user run as root.
                    529: #   - Connecting with lonc rather than lond directly ensuring this is a loncapa
                    530: #     host
                    531: #   - We must appear in the remote host's hosts.tab file.
                    532: #   - The host must appear in our hosts.tab file.
                    533: #
                    534: #  Parameters:
                    535: #     tablename - must be one of hosts or domain.
                    536: #     tablefile - name of the file containing the table to push.
                    537: #     host      - name of the host to push this file to.     
                    538: #
1.26    ! foxr      539: #    
1.13      foxr      540: #
1.7       foxr      541: sub PushFile {
                    542:     my $tablename = shift;
                    543:     my $tablefile = shift;
                    544:     my $host      = shift;
                    545:     
1.8       foxr      546:     # Open the table file:
                    547: 
1.26    ! foxr      548:    if(!open(TABLEFILE, "<$tablefile")) {
        !           549:       die "ENOENT - No such file or directory $tablefile";
        !           550:    }
1.8       foxr      551:   
                    552:     # Require that the host be valid:
                    553: 
1.26    ! foxr      554:    if(!ValidHost($host)) {
        !           555:       die "EHOSTINVAL - Invalid host $host"; # Ok so I invented this 'errno'.
        !           556:    }
1.8       foxr      557:     # Read in the file.  If the table name is valid, push it.
                    558: 
1.26    ! foxr      559:    my @table = <TABLEFILE>;	#  These files are pretty small.
        !           560:    close TABLEFILE;
1.8       foxr      561: 
1.26    ! foxr      562:    if( ($tablename eq "host")    ||
        !           563:        ($tablename eq "domain")) {
        !           564:       print("Pushing $tablename to $host\n");
        !           565:       Transact($host, "pushfile:$tablename",\@table);
        !           566:    } else {
        !           567:       die "EINVAL - Invalid parameter. tablename: $tablename must be host or domain";
        !           568:    }
        !           569: }
        !           570: #
        !           571: #   This function forms and executes an edit file with a
        !           572: #   remote lond server.  We build the full transaction string
        !           573: #   and use Transact to perform the transaction.
        !           574: #   Paramters:
        !           575: #      host     - loncapa name of host to operate on.
        !           576: #      body     - Body of the command.  We send:
        !           577: #                  edit:$body as the command request.
        !           578: #
        !           579: sub EditFile {
        !           580:    my $host    = shift;
        !           581:    my $body    = shift;
        !           582:    
        !           583:    if(!ValidHost($host)) {
        !           584:       die "EHOSTINVAL - Invalid host $host";
        !           585:    }
        !           586:    Transact($host, "edit", $body);
1.7       foxr      587: }
1.26    ! foxr      588: 
1.9       foxr      589: #
                    590: #   This function is called to reinitialize a server in a remote host.
                    591: #   The servers that can be reinitialized are:
                    592: #   - lonc   - The lonc client process.
                    593: #   - lond   - The lond daemon.
                    594: #  NOTE:
                    595: #    Reinitialization in this case means re-scanning the hosts table,
                    596: #    starting new lond/lonc's as approprate and stopping existing lonc/lond's.
                    597: #
                    598: #  Parameters:
                    599: #     process - The name of the process to reinit (lonc or lond).
                    600: #     host    - The host in which this reinit will happen.
                    601: #
1.13      foxr      602: #   >>>BUGBUG<<<< This belongs  in lonnet.pm
                    603: #
1.9       foxr      604: sub ReinitProcess {
1.26    ! foxr      605:    my $process = shift;
        !           606:    my $host    = shift;
1.3       foxr      607: 
1.9       foxr      608:     #  Ensure the host is valid:
                    609:     
1.26    ! foxr      610:    if(!ValidHost($host)) {
        !           611:       die "EHOSTINVAL - Invalid host $host";
        !           612:    }
1.9       foxr      613:     # Ensure target process selector is valid:
                    614: 
1.26    ! foxr      615:    if(($process eq "lonc") ||
        !           616:       ($process eq "lond")) {
        !           617:       print("Reinitializing $process in $host\n");
        !           618:       Transact($host, "reinit:$process");
        !           619:    } else {
        !           620:       die "EINVAL -Invalid parameter. Process $process must be lonc or lond";
        !           621:    }
1.7       foxr      622: }
1.6       foxr      623: #--------------------------- Entry point: --------------------------
                    624: 
1.16      foxr      625: 
                    626: 
1.6       foxr      627: #  Parse the parameters
                    628: #  If command parsing failed, then print usage:
1.2       foxr      629: 
1.7       foxr      630: my @params   = ParseArgs;
                    631: my $nparam   = @params;
1.3       foxr      632: 
                    633: if($nparam == 0) {
1.2       foxr      634:     Usage;
1.4       foxr      635:     exit -1;
1.2       foxr      636: }
1.7       foxr      637: #
                    638: #   Next, ensure we are running as EID root.
                    639: #
                    640: if ($EUID != 0) {
                    641:     die "ENOPRIV - No privilege for requested operation"
1.6       foxr      642: }
                    643: 
1.19      foxr      644: #
                    645: #   Read the configuration file.
                    646: #   
                    647: 
                    648: ReadConfig;			# Read the configuration info (incl.hosts).
1.4       foxr      649: 
1.6       foxr      650: #   Based on the operation requested invoke the appropriate function:
                    651: 
1.7       foxr      652: my $operation = shift @params;
1.6       foxr      653: 
                    654: if($operation eq "push") {  # push tablename filename host
1.7       foxr      655:     my $tablename = shift @params;
                    656:     my $tablefile = shift @params;
                    657:     my $host      = shift @params;
1.16      foxr      658:     if($host) {
1.26    ! foxr      659:       PushFile($tablename, $tablefile, $host);
1.16      foxr      660:     } else {			# Push to whole cluster.
1.26    ! foxr      661:       foreach my $host (keys %hostshash) {
        !           662:          PushFile($tablename, $tablefile, $host);
        !           663:       }
1.16      foxr      664:     }
1.6       foxr      665: 
1.7       foxr      666: } elsif($operation eq "reinit") {	# reinit processname host.
                    667:     my $process   = shift @params;
                    668:     my $host      = shift @params;
1.16      foxr      669:     if ($host) {
                    670: 	ReinitProcess($process, $host);
                    671:     } else {			# Reinit whole cluster.
                    672: 	foreach my $host (keys %hostshash) {
                    673: 	    ReinitProcess($process,$host);
                    674: 	}
                    675:     }
1.26    ! foxr      676: } elsif($operation eq "edit") {   # Edit a table.
        !           677:    my $tablename     = shift @params;
        !           678:    my $scriptfile    = shift @params;
        !           679:    my $host          = shift @params;
        !           680:    my $CommandBody   = BuildEditScript($tablename, $scriptfile);
        !           681:    if ($host) {
        !           682:       EditFile($host, $CommandBody);
        !           683:    } else {
        !           684:       foreach my $ClusterMember (keys %hostshash) {
        !           685:          EditFile($ClusterMember, $CommandBody);
        !           686:       }
        !           687:    }
        !           688: }
1.7       foxr      689: else {
1.26    ! foxr      690:    Usage;
1.6       foxr      691: }
1.4       foxr      692: exit 0;
1.2       foxr      693: 
                    694: =head1 NAME
                    695:     lonManage - Command line utility for remote management of lonCAPA
                    696:     cluster nodes.
                    697: 
                    698: =head1 SYNOPSIS
                    699: 
                    700: Usage:
1.3       foxr      701:     B<lonManage  --push=<tablename>  newfile  host>
1.2       foxr      702:         Push <tablename> to the lonTabs directory.  Note that
                    703:         <tablename> must be one of:
                    704:            hosts  (hosts.tab)
                    705:            domain (domain.tab)
                    706: 
1.3       foxr      707:     B<lonManage  --reinit=lonc host>
1.2       foxr      708:            Sends a HUP signal to the remote systems's lond.
                    709: 
1.26    ! foxr      710:     B<lonManage  --reinit=lond host>
1.2       foxr      711:           Requests the remote system's lond perform the same action as if
                    712:           it had received a HUP signal.
                    713: 
1.26    ! foxr      714:     B<lonManage  --edit=<tablename> editscript host>
        !           715:          Requests the remote system's lond perform an edit
        !           716:          on <tablename>  editscript supplies a set of 
        !           717:          editing commands.  Each edit command is one of :
        !           718:          
        !           719:          append|key|newline
        !           720:          delete|key|
        !           721:          replace|key|newline
        !           722:          
        !           723:          The key above is the value of the loncapa host name
        !           724:          in the file.
        !           725:          
        !           726: In the above syntax, the host above is the 
        !           727: hosts.tab name of a host,
        !           728: not the IP address of the host.
1.2       foxr      729: 
                    730: 
                    731: =head1 DESCRIPTION
                    732: 
                    733: =head1 PREREQUISITES
1.3       foxr      734: 
1.7       foxr      735: =item strict
1.3       foxr      736: =item Getopt::Long
1.7       foxr      737: =item English
1.13      foxr      738: =item IO::Socket::UNIX
1.26    ! foxr      739: =item LONCAPA::LondConnection
1.13      foxr      740: 
                    741: =head1 KEY Subroutines.
1.2       foxr      742: 
                    743: =head1  CATEGORIES
                    744:     Command line utility
                    745: 
                    746: =cut

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