Annotation of loncom/lonManage, revision 1.27

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.27    ! foxr        6: #  $Id: lonManage,v 1.26 2003/12/22 11:02:36 foxr Exp $
1.1       foxr        7: #
1.27    ! foxr        8: # $Id: lonManage,v 1.26 2003/12/22 11:02:36 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|".
1.27    ! foxr      424:          "nscll2|nscl\:library\:lonkashy.nscl.msu.edu\:35.8.32.89\n"
        !           425: 	."delete|nscll2"
1.26      foxr      426:       );
                    427:    return \@EditScript;
                    428: }
1.19      foxr      429: #  Read the loncapa configuration stuff.  If ForeignHostTab is empty,
                    430: #  assume we are part of a loncapa cluster and read the hosts.tab
                    431: #  file from the config directory.  Otherwise, ForeignHossTab
                    432: #  is the name of an alternate configuration file to read in 
                    433: #  standalone mode.
1.11      foxr      434: #
                    435: sub ReadConfig {
1.19      foxr      436: 
1.26      foxr      437: 
                    438:    
                    439:    if($ForeignHostTab eq "") {
                    440:        my $perlvarref = LondConnection::read_conf('loncapa.conf');
                    441:        %perlvar    = %{$perlvarref};
                    442:        my $hoststab   = LondConnection::read_hosts(
                    443: 						   "$perlvar{lonTabDir}/hosts.tab");
                    444:       %hostshash     = %{$hoststab};
                    445:       $MyHost        = $perlvar{lonHostID}; # Set hostname from vars.
                    446:       $ServerPort    = $perlvar{londPort};
                    447:    } else {
1.23      foxr      448: 	
1.26      foxr      449:       LondConnection::ReadForeignConfig($MyHost, 
                    450:                                         $ForeignHostTab);
                    451:       my $hoststab = LondConnection::read_hosts($ForeignHostTab); #  we need to know too.
                    452: 	   %hostshash   = %{$hoststab};
                    453: 	   $ServerPort    = $DefaultServerPort;
                    454:    }
1.11      foxr      455: }
                    456: #
1.10      foxr      457: #  Determine if the target host is valid.
                    458: #  This is done by reading the current hosts.tab file.
                    459: #  For the host to be valid, it must be inthe file.
                    460: #
                    461: #  Parameters:
                    462: #     host   - Name of host to check on.
                    463: #  Returns:
                    464: #     true   if host is valid.
                    465: #     false  if host is invalid.
                    466: #
1.8       foxr      467: sub ValidHost {
1.10      foxr      468:     my $host       = shift;
1.11      foxr      469:    
1.10      foxr      470: 
                    471:     return defined $hostshash{$host};
                    472: 
1.8       foxr      473: }
1.13      foxr      474: 
                    475: 
                    476: 
1.12      foxr      477: #
                    478: #  Performs a transaction with lonc.
                    479: #  By the time this is called, the transaction has already been
                    480: #  validated by the caller.
                    481: #
                    482: #   Parameters:
                    483: #
                    484: #   host    - hosts.tab name of the host whose lonc we'll be talking to.
                    485: #   command - The base command we'll be asking lond to execute.
                    486: #   body    - [optional] If supplied, this is a command body that is a ref.
                    487: #             to an array of lines that will be appended to the 
                    488: #             command.
                    489: #
                    490: #  NOTE:
                    491: #    The command will be done as an encrypted operation.
                    492: #
1.8       foxr      493: sub Transact {
1.12      foxr      494:     my $host    = shift;
                    495:     my $command = shift;
                    496:     my $haveBody= 0;
                    497:     my $body;
                    498:     my $i;
                    499: 
1.26      foxr      500:    if(scalar @ARG) {
                    501:       $body = shift;
                    502:       $haveBody = 1;
                    503:    }
1.12      foxr      504:     #  Construct the command to send to the server:
                    505:     
1.26      foxr      506:    my $request = "encrypt\:";	# All requests are encrypted.
                    507:    $request   .= $command;
                    508:    if($haveBody) {
                    509:       $request .= "\:";
                    510:       my $bodylines = scalar @$body;
                    511:       for($i = 0; $i < $bodylines; $i++) {
                    512:          $request .= $$body[$i];
                    513:       }
                    514:    } else {
                    515:       $request .= "\n";
                    516:    }
1.13      foxr      517:     # Body is now built... transact with lond..
                    518:     
                    519:     my $answer = subreply($request, $host);
                    520: 
                    521:     print "$answer\n";
1.10      foxr      522: 
1.8       foxr      523: }
1.7       foxr      524: #
                    525: #   Called to push a file to the remote system.
                    526: #   The only legal files to push are hosts.tab and domain.tab.
                    527: #   Security is somewhat improved by
                    528: #   
                    529: #   - Requiring the user run as root.
                    530: #   - Connecting with lonc rather than lond directly ensuring this is a loncapa
                    531: #     host
                    532: #   - We must appear in the remote host's hosts.tab file.
                    533: #   - The host must appear in our hosts.tab file.
                    534: #
                    535: #  Parameters:
                    536: #     tablename - must be one of hosts or domain.
                    537: #     tablefile - name of the file containing the table to push.
                    538: #     host      - name of the host to push this file to.     
                    539: #
1.26      foxr      540: #    
1.13      foxr      541: #
1.7       foxr      542: sub PushFile {
                    543:     my $tablename = shift;
                    544:     my $tablefile = shift;
                    545:     my $host      = shift;
                    546:     
1.8       foxr      547:     # Open the table file:
                    548: 
1.26      foxr      549:    if(!open(TABLEFILE, "<$tablefile")) {
                    550:       die "ENOENT - No such file or directory $tablefile";
                    551:    }
1.8       foxr      552:   
                    553:     # Require that the host be valid:
                    554: 
1.26      foxr      555:    if(!ValidHost($host)) {
                    556:       die "EHOSTINVAL - Invalid host $host"; # Ok so I invented this 'errno'.
                    557:    }
1.8       foxr      558:     # Read in the file.  If the table name is valid, push it.
                    559: 
1.26      foxr      560:    my @table = <TABLEFILE>;	#  These files are pretty small.
                    561:    close TABLEFILE;
1.8       foxr      562: 
1.26      foxr      563:    if( ($tablename eq "host")    ||
                    564:        ($tablename eq "domain")) {
                    565:       print("Pushing $tablename to $host\n");
                    566:       Transact($host, "pushfile:$tablename",\@table);
                    567:    } else {
                    568:       die "EINVAL - Invalid parameter. tablename: $tablename must be host or domain";
                    569:    }
                    570: }
                    571: #
                    572: #   This function forms and executes an edit file with a
                    573: #   remote lond server.  We build the full transaction string
                    574: #   and use Transact to perform the transaction.
                    575: #   Paramters:
                    576: #      host     - loncapa name of host to operate on.
                    577: #      body     - Body of the command.  We send:
                    578: #                  edit:$body as the command request.
                    579: #
                    580: sub EditFile {
                    581:    my $host    = shift;
                    582:    my $body    = shift;
                    583:    
                    584:    if(!ValidHost($host)) {
                    585:       die "EHOSTINVAL - Invalid host $host";
                    586:    }
                    587:    Transact($host, "edit", $body);
1.7       foxr      588: }
1.26      foxr      589: 
1.9       foxr      590: #
                    591: #   This function is called to reinitialize a server in a remote host.
                    592: #   The servers that can be reinitialized are:
                    593: #   - lonc   - The lonc client process.
                    594: #   - lond   - The lond daemon.
                    595: #  NOTE:
                    596: #    Reinitialization in this case means re-scanning the hosts table,
                    597: #    starting new lond/lonc's as approprate and stopping existing lonc/lond's.
                    598: #
                    599: #  Parameters:
                    600: #     process - The name of the process to reinit (lonc or lond).
                    601: #     host    - The host in which this reinit will happen.
                    602: #
1.13      foxr      603: #   >>>BUGBUG<<<< This belongs  in lonnet.pm
                    604: #
1.9       foxr      605: sub ReinitProcess {
1.26      foxr      606:    my $process = shift;
                    607:    my $host    = shift;
1.3       foxr      608: 
1.9       foxr      609:     #  Ensure the host is valid:
                    610:     
1.26      foxr      611:    if(!ValidHost($host)) {
                    612:       die "EHOSTINVAL - Invalid host $host";
                    613:    }
1.9       foxr      614:     # Ensure target process selector is valid:
                    615: 
1.26      foxr      616:    if(($process eq "lonc") ||
                    617:       ($process eq "lond")) {
                    618:       print("Reinitializing $process in $host\n");
                    619:       Transact($host, "reinit:$process");
                    620:    } else {
                    621:       die "EINVAL -Invalid parameter. Process $process must be lonc or lond";
                    622:    }
1.7       foxr      623: }
1.6       foxr      624: #--------------------------- Entry point: --------------------------
                    625: 
1.16      foxr      626: 
                    627: 
1.6       foxr      628: #  Parse the parameters
                    629: #  If command parsing failed, then print usage:
1.2       foxr      630: 
1.7       foxr      631: my @params   = ParseArgs;
                    632: my $nparam   = @params;
1.3       foxr      633: 
                    634: if($nparam == 0) {
1.2       foxr      635:     Usage;
1.4       foxr      636:     exit -1;
1.2       foxr      637: }
1.7       foxr      638: #
                    639: #   Next, ensure we are running as EID root.
                    640: #
                    641: if ($EUID != 0) {
                    642:     die "ENOPRIV - No privilege for requested operation"
1.6       foxr      643: }
                    644: 
1.19      foxr      645: #
                    646: #   Read the configuration file.
                    647: #   
                    648: 
                    649: ReadConfig;			# Read the configuration info (incl.hosts).
1.4       foxr      650: 
1.6       foxr      651: #   Based on the operation requested invoke the appropriate function:
                    652: 
1.7       foxr      653: my $operation = shift @params;
1.6       foxr      654: 
                    655: if($operation eq "push") {  # push tablename filename host
1.7       foxr      656:     my $tablename = shift @params;
                    657:     my $tablefile = shift @params;
                    658:     my $host      = shift @params;
1.16      foxr      659:     if($host) {
1.26      foxr      660:       PushFile($tablename, $tablefile, $host);
1.16      foxr      661:     } else {			# Push to whole cluster.
1.26      foxr      662:       foreach my $host (keys %hostshash) {
                    663:          PushFile($tablename, $tablefile, $host);
                    664:       }
1.16      foxr      665:     }
1.6       foxr      666: 
1.7       foxr      667: } elsif($operation eq "reinit") {	# reinit processname host.
                    668:     my $process   = shift @params;
                    669:     my $host      = shift @params;
1.16      foxr      670:     if ($host) {
                    671: 	ReinitProcess($process, $host);
                    672:     } else {			# Reinit whole cluster.
                    673: 	foreach my $host (keys %hostshash) {
                    674: 	    ReinitProcess($process,$host);
                    675: 	}
                    676:     }
1.26      foxr      677: } elsif($operation eq "edit") {   # Edit a table.
                    678:    my $tablename     = shift @params;
                    679:    my $scriptfile    = shift @params;
                    680:    my $host          = shift @params;
                    681:    my $CommandBody   = BuildEditScript($tablename, $scriptfile);
                    682:    if ($host) {
                    683:       EditFile($host, $CommandBody);
                    684:    } else {
                    685:       foreach my $ClusterMember (keys %hostshash) {
                    686:          EditFile($ClusterMember, $CommandBody);
                    687:       }
                    688:    }
                    689: }
1.7       foxr      690: else {
1.26      foxr      691:    Usage;
1.6       foxr      692: }
1.4       foxr      693: exit 0;
1.2       foxr      694: 
                    695: =head1 NAME
                    696:     lonManage - Command line utility for remote management of lonCAPA
                    697:     cluster nodes.
                    698: 
                    699: =head1 SYNOPSIS
                    700: 
                    701: Usage:
1.3       foxr      702:     B<lonManage  --push=<tablename>  newfile  host>
1.2       foxr      703:         Push <tablename> to the lonTabs directory.  Note that
                    704:         <tablename> must be one of:
                    705:            hosts  (hosts.tab)
                    706:            domain (domain.tab)
                    707: 
1.3       foxr      708:     B<lonManage  --reinit=lonc host>
1.2       foxr      709:            Sends a HUP signal to the remote systems's lond.
                    710: 
1.26      foxr      711:     B<lonManage  --reinit=lond host>
1.2       foxr      712:           Requests the remote system's lond perform the same action as if
                    713:           it had received a HUP signal.
                    714: 
1.26      foxr      715:     B<lonManage  --edit=<tablename> editscript host>
                    716:          Requests the remote system's lond perform an edit
                    717:          on <tablename>  editscript supplies a set of 
                    718:          editing commands.  Each edit command is one of :
                    719:          
                    720:          append|key|newline
                    721:          delete|key|
                    722:          replace|key|newline
                    723:          
                    724:          The key above is the value of the loncapa host name
                    725:          in the file.
                    726:          
                    727: In the above syntax, the host above is the 
                    728: hosts.tab name of a host,
                    729: not the IP address of the host.
1.2       foxr      730: 
                    731: 
                    732: =head1 DESCRIPTION
                    733: 
                    734: =head1 PREREQUISITES
1.3       foxr      735: 
1.7       foxr      736: =item strict
1.3       foxr      737: =item Getopt::Long
1.7       foxr      738: =item English
1.13      foxr      739: =item IO::Socket::UNIX
1.26      foxr      740: =item LONCAPA::LondConnection
1.13      foxr      741: 
                    742: =head1 KEY Subroutines.
1.2       foxr      743: 
                    744: =head1  CATEGORIES
                    745:     Command line utility
                    746: 
                    747: =cut

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