Annotation of loncom/lonManage, revision 1.29

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

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