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