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