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