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