--- loncom/Attic/lonManage 2003/08/12 10:40:44 1.4 +++ loncom/Attic/lonManage 2003/09/08 09:45:20 1.14 @@ -3,9 +3,9 @@ # # lonManage supports remote management of nodes in a LonCAPA cluster. # -# $Id: lonManage,v 1.4 2003/08/12 10:40:44 foxr Exp $ +# $Id: lonManage,v 1.14 2003/09/08 09:45:20 foxr Exp $ # -# $Id: lonManage,v 1.4 2003/08/12 10:40:44 foxr Exp $ +# $Id: lonManage,v 1.14 2003/09/08 09:45:20 foxr Exp $ # # Copyright Michigan State University Board of Trustees # @@ -50,6 +50,47 @@ # not the IP address of the host. # # $Log: lonManage,v $ +# Revision 1.14 2003/09/08 09:45:20 foxr +# 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). +# +# Revision 1.13 2003/08/19 10:26:24 foxr +# Initial working version... tested against an unmodified lond this +# produces an unknown_cmd response which is about what I'd expect. +# +# Revision 1.12 2003/08/18 11:08:07 foxr +# Debug request building in Transact. +# +# Revision 1.11 2003/08/18 10:45:32 foxr +# Felt strongly enough about hoisting ReadConfiguration into a separate sub +# that I did it now before I forgot. +# +# Revision 1.10 2003/08/18 10:43:31 foxr +# Code/test ValidHost. The hosts.tab and the perl variables are read in as +# global hashes as a side effect. May later want to clean this up by making +# a separate getconfig function and hoisting the config reads into that. +# +# Revision 1.9 2003/08/18 10:25:46 foxr +# Write ReinitProcess function in terms of ValidHost and Transact. +# +# Revision 1.8 2003/08/18 10:18:21 foxr +# Completed PushFile function in terms of +# - ValidHost - Determines if target host is valid. +# - Transact - Performs one of the valid transactions with the +# appropriate lonc<-->lond client/server pairs. +# +# Revision 1.7 2003/08/18 09:56:01 foxr +# 1. Require to be run as root. +# 2. Catch case where no operation switch is supplied and put out usage. +# 3. skeleton/comments for PushFile function. +# +# Revision 1.6 2003/08/12 11:02:59 foxr +# Implement command switch dispatching. +# +# Revision 1.5 2003/08/12 10:55:42 foxr +# Complete command line parsing (tested) +# # Revision 1.4 2003/08/12 10:40:44 foxr # Get switch parsing right. # @@ -60,8 +101,25 @@ # Add usage and skeleton documentation. # # + + + +# Modules required: + +use strict; # Because it's good practice. +use English; # Cause I like meaningful names. use Getopt::Long; +use LONCAPA::Configuration; # To handle configuration I/O. +use IO::Socket::UNIX; # To communicate with lonc. + +# File scoped variables: + +my %perlvar; # Perl variable defs from apache config. +my %hostshash; # Host table as a host indexed hash. +# +# prints out utility's command usage info. +# sub Usage { print "Usage:"; print <new(Peer =>"$peerfile", + Type => SOCK_STREAM, + Timeout => 10) + or return "con_lost"; + print $client "$cmd\n"; + my $answer=<$client>; + if (!$answer) { $answer="con_lost"; } + chomp($answer); + return $answer; +} +# >>> BUGBUG <<< # # Use Getopt::Long to parse the parameters of the program. # @@ -110,7 +191,8 @@ USAGE sub ParseArgs { my $pushing = ''; - my $reiniting = ''; + my $reinitting = ''; + if(!GetOptions('push=s' => \$pushing, 'reinit=s' => \$reinitting)) { return (); @@ -118,17 +200,34 @@ sub ParseArgs { # Require exactly one of --push and --reinit - my $command = ''; + my $command = ''; my $commandarg = ''; + my $paramcount = @ARGV; # Number of additional arguments. + + if($pushing ne '') { + + # --push takes in addition a table, and a host: + # + if($paramcount != 2) { + return (); # Invalid parameter count. + } if($command ne '') { return (); } else { + $command = 'push'; $commandarg = $pushing; } } + if ($reinitting ne '') { + + # --reinit takes in addition just a host name + + if($paramcount != 1) { + return (); + } if($command ne '') { return (); } else { @@ -137,21 +236,213 @@ sub ParseArgs { } } - return ($command, $commandarg); + # Build the result list: + + my @result = ($command, $commandarg); + my $i; + for($i = 0; $i < $paramcount; $i++) { + push(@result, $ARGV[$i]); + } + + return @result; +} +# +# Read the loncapa configuration stuff. +# +sub ReadConfig { + my $perlvarref = LONCAPA::Configuration::read_conf('loncapa.conf'); + %perlvar = %{$perlvarref}; + my $hoststab = LONCAPA::Configuration::read_hosts( + "$perlvar{'lonTabDir'}/hosts.tab"); + %hostshash = %{$hoststab}; + +} +# +# Determine if the target host is valid. +# This is done by reading the current hosts.tab file. +# For the host to be valid, it must be inthe file. +# +# Parameters: +# host - Name of host to check on. +# Returns: +# true if host is valid. +# false if host is invalid. +# +sub ValidHost { + my $host = shift; + + ReadConfig; + + return defined $hostshash{$host}; + +} + + + +# +# Performs a transaction with lonc. +# By the time this is called, the transaction has already been +# validated by the caller. +# +# Parameters: +# +# host - hosts.tab name of the host whose lonc we'll be talking to. +# command - The base command we'll be asking lond to execute. +# body - [optional] If supplied, this is a command body that is a ref. +# to an array of lines that will be appended to the +# command. +# +# NOTE: +# The command will be done as an encrypted operation. +# +sub Transact { + my $host = shift; + my $command = shift; + my $haveBody= 0; + my $body; + my $i; + + if(scalar @ARG) { + $body = shift; + $haveBody = 1; + } + # Construct the command to send to the server: + + my $request = "encrypt\:"; # All requests are encrypted. + $request .= $command; + if($haveBody) { + $request .= "\:"; + my $bodylines = scalar @$body; + for($i = 0; $i < $bodylines; $i++) { + $request .= $$body[$i]; + } + } else { + $request .= "\n"; + } + # Body is now built... transact with lond.. + + my $answer = subreply($request, $host); + + print "$answer\n"; + } +# +# Called to push a file to the remote system. +# The only legal files to push are hosts.tab and domain.tab. +# Security is somewhat improved by +# +# - Requiring the user run as root. +# - Connecting with lonc rather than lond directly ensuring this is a loncapa +# host +# - We must appear in the remote host's hosts.tab file. +# - The host must appear in our hosts.tab file. +# +# Parameters: +# tablename - must be one of hosts or domain. +# tablefile - name of the file containing the table to push. +# host - name of the host to push this file to. +# +# >>>BUGBUG<<< This belongs in lonnet.pm. +# +sub PushFile { + my $tablename = shift; + my $tablefile = shift; + my $host = shift; + + # Open the table file: + + if(!open(TABLEFILE, "<$tablefile")) { + die "ENOENT - No such file or directory $tablefile"; + } + + # Require that the host be valid: + if(!ValidHost($host)) { + die "EHOSTINVAL - Invalid host $host"; # Ok so I invented this 'errno'. + } + # Read in the file. If the table name is valid, push it. + + my @table = ; # These files are pretty small. + close TABLEFILE; + + if( ($tablename eq "host") || + ($tablename eq "domain")) { + Transact($host, "pushfile:$tablename",\@table); + } else { + die "EINVAL - Invalid parameter. tablename: $tablename must be host or domain"; + } +} # -# If command parsing failed, then print usage: +# This function is called to reinitialize a server in a remote host. +# The servers that can be reinitialized are: +# - lonc - The lonc client process. +# - lond - The lond daemon. +# NOTE: +# Reinitialization in this case means re-scanning the hosts table, +# starting new lond/lonc's as approprate and stopping existing lonc/lond's. +# +# Parameters: +# process - The name of the process to reinit (lonc or lond). +# host - The host in which this reinit will happen. +# +# >>>BUGBUG<<<< This belongs in lonnet.pm +# +sub ReinitProcess { + my $process = shift; + my $host = shift; + + # Ensure the host is valid: + + if(!ValidHost($host)) { + die "EHOSTINVAL - Invalid host $host"; + } + # Ensure target process selector is valid: + + if(($process eq "lonc") || + ($process eq "lond")) { + Transact($host, "reinit:$process"); + } else { + die "EINVAL -Invalid parameter. Process $process must be lonc or lond"; + } +} +#--------------------------- Entry point: -------------------------- + +# Parse the parameters +# If command parsing failed, then print usage: -@status = ParseArgs; -$nparam = @status; +my @params = ParseArgs; +my $nparam = @params; if($nparam == 0) { Usage; exit -1; } -print "Will do a $status[0] : $status[1]\n"; +# +# Next, ensure we are running as EID root. +# +if ($EUID != 0) { + die "ENOPRIV - No privilege for requested operation" +} + + +# Based on the operation requested invoke the appropriate function: + +my $operation = shift @params; +if($operation eq "push") { # push tablename filename host + my $tablename = shift @params; + my $tablefile = shift @params; + my $host = shift @params; + PushFile($tablename, $tablefile, $host); + +} elsif($operation eq "reinit") { # reinit processname host. + my $process = shift @params; + my $host = shift @params; + ReinitProcess($process, $host); +} +else { + Usage; +} exit 0; =head1 NAME @@ -182,7 +473,12 @@ Usage: =head1 PREREQUISITES +=item strict =item Getopt::Long +=item English +=item IO::Socket::UNIX + +=head1 KEY Subroutines. =head1 CATEGORIES Command line utility 500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.