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