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