version 1.15, 2003/09/16 09:49:54
|
version 1.24, 2003/11/04 11:36:04
|
Line 33
|
Line 33
|
# it is a command line tool. The following command line syntax (usage) |
# it is a command line tool. The following command line syntax (usage) |
# is supported: |
# is supported: |
# |
# |
# lonManage -push <tablename> newfile host |
# lonManage -push <tablename> newfile [host] |
# Push <tablename> to the lonTabs directory. Note that |
# Push <tablename> to the lonTabs directory. Note that |
# <tablename> must be one of: |
# <tablename> must be one of: |
# host (hosts.tab) |
# host (hosts.tab) |
# domain (domain.tab) |
# domain (domain.tab) |
# |
# |
# lonManage -reinit lonc host |
# lonManage -reinit lonc [host] |
# Sends a HUP signal to the remote systems's lond. |
# Sends a HUP signal to the remote systems's lond. |
# |
# |
# lonmanage -reinit lond host |
# lonmanage -reinit lond [host] |
# Requests the remote system's lond perform the same action as if |
# Requests the remote system's lond perform the same action as if |
# it had received a HUP signal. |
# it had received a HUP signal. |
# |
# |
# In the above syntax, the host above is the hosts.tab name of a host, |
# In the above syntax, the host above is the hosts.tab name of a host, |
# not the IP address of the host. |
# not the IP address of the host |
# |
# |
# $Log$ |
# If [host] is not supplied, every host in the client's hosts.tab |
# Revision 1.15 2003/09/16 09:49:54 foxr |
# table is iterated through and procesed.. |
# Adjust the usage message to reflect what actually will happen on |
|
# --reinit={lond|lonc} |
|
# |
|
# 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. |
|
# |
|
# Revision 1.3 2003/08/12 10:22:35 foxr |
|
# Put in parameter parsing infrastructure |
|
# |
|
# Revision 1.2 2003/08/12 09:58:49 foxr |
|
# Add usage and skeleton documentation. |
|
# |
# |
# |
# |
|
|
Line 110
|
Line 58
|
|
|
# Modules required: |
# Modules required: |
|
|
|
use lib "."; |
|
|
use strict; # Because it's good practice. |
use strict; # Because it's good practice. |
use English; # Cause I like meaningful names. |
use English; # Cause I like meaningful names. |
use Getopt::Long; |
use Getopt::Long; |
use LONCAPA::Configuration; # To handle configuration I/O. |
use LondConnection; |
use IO::Socket::UNIX; # To communicate with lonc. |
use IO::Poll qw(POLLRDNORM POLLWRNORM POLLIN POLLHUP POLLOUT); |
|
|
# File scoped variables: |
# File scoped variables: |
|
|
my %perlvar; # Perl variable defs from apache config. |
my %perlvar; # Perl variable defs from apache config. |
my %hostshash; # Host table as a host indexed hash. |
my %hostshash; # Host table as a host indexed hash. |
|
|
|
my $MyHost=""; # Host name to use as me. |
|
my $ForeignHostTab=""; # Name of foreign hosts table. |
|
|
|
my $DefaultServerPort = 5663; # Default server port if standalone. |
|
my $ServerPort; # Port used to connect to lond. |
|
|
|
my $TransitionTimeout = 5; # Poll timeout in seconds. |
|
|
|
|
|
# LondConnection::SetDebug(10); |
|
|
|
|
# |
# |
# prints out utility's command usage info. |
# prints out utility's command usage info. |
# |
# |
sub Usage { |
sub Usage { |
print "Usage:"; |
print "Usage:"; |
print <<USAGE; |
print <<USAGE; |
lonManage --push=<tablename> newfile host |
lonManage [--myname=host --hosts=table] --push=<tablename> newfile [host] |
Push <tablename> to the lonTabs directory. Note that |
Push <tablename> to the lonTabs directory. Note that |
<tablename> must be one of: |
<tablename> must be one of: |
host (hosts.tab) |
host (hosts.tab) |
domain (domain.tab) |
domain (domain.tab) |
|
|
lonManage --reinit=lonc host |
lonManage [--myname=host --hosts=table] --reinit=lonc [host] |
Causes lonc in the remote system to reread hosts.tab and |
Causes lonc in the remote system to reread hosts.tab and |
adjust the set of clients that are being maintained to match |
adjust the set of clients that are being maintained to match |
the new file. |
the new file. |
|
|
|
|
lonManage --reinit=lond host |
lonManage [--myname=host --hosts=table] --reinit=lond [host] |
Causes lond in the remote system to reread the hosts.tab file |
Causes lond in the remote system to reread the hosts.tab file |
and adjust the set of servers to match changes in that file. |
and adjust the set of servers to match changes in that file. |
|
|
In the above syntax, the host above is the hosts.tab name of a host, |
In the above syntax, the host above is the hosts.tab name of a host, |
not the IP address of the host. |
not the IP address of the host. |
|
|
|
If [host] is omitted, all hosts in the hosts.tab file are iterated |
|
over. |
|
|
|
For all of the above syntaxes if --myname=host and --hosts=table are |
|
supplied (both must be present), the utility runs in standalone mode |
|
presenting itself to the world as 'host' and using the hosts.tab file |
|
specified in the --hosts switch. |
USAGE |
USAGE |
|
|
|
|
} |
} |
|
|
# |
# |
# Lifted from lonnet.pm - and we need to figure out a way to get it back in. |
# Make a direct connection to the lond in 'host'. The port is |
# Performas a transaction with lond via the lonc proxy server. |
# gotten from the global variable: ServerPort. |
|
# Returns: |
|
# The connection or undef if one could not be formed. |
|
# |
|
sub MakeLondConnection { |
|
my $host = shift; |
|
|
|
my $Connection = LondConnection->new($host, $ServerPort); |
|
return return $Connection; |
|
} |
|
# |
|
# This function runs through the section of the connection |
|
# state machine that has to do with negotiating the startup |
|
# sequence with lond. The general strategy is to loop |
|
# until the connection state becomes idle or disconnected. |
|
# Disconnected indicates an error or rejection of the |
|
# connection at some point in the negotiation. |
|
# idle indicates a connection ready for a request. |
|
# The main loop consults the object to determine if it |
|
# wants to be writeable or readable, waits for that |
|
# condition on the socket (with timeout) and then issues |
|
# the appropriate LondConnection call. Note that |
|
# LondConnection is capable of doing everything necessary |
|
# to get to the initial idle state. |
|
# |
|
# |
|
# Parameters: |
|
# connection - A connection that has been created with |
|
# the remote lond. This connection should |
|
# be in the Connected state ready to send |
|
# the init sequence. |
|
# |
|
sub NegotiateStartup { |
|
my $connection = shift; |
|
my $returnstatus = "ok"; # Optimistic!!. |
|
|
|
my $state = $connection->GetState; |
|
if($state ne "Connected") { |
|
print "Error: Initial lond connection state: $state should be Connected\n"; |
|
return "error"; |
|
} |
|
my $Socket = $connection->GetSocket; # This is a IO:Socket::INET object. |
|
|
|
# Ready now to enter the main loop: |
|
# |
|
my $error = 0; |
|
while (($connection->GetState ne "Idle") && (!$error)) { |
|
# |
|
# Wait for the socket to get into the appropriate state: |
|
# |
|
my $wantread = $connection->WantReadable; |
|
my $poll = new IO::Poll; |
|
$poll->mask($Socket => $wantread ? POLLIN : POLLOUT); |
|
$poll->poll($TransitionTimeout); |
|
my $done = $poll->handles(); |
|
if(scalar($done) == 0) { # Timeout!!! |
|
print "Error: Timeout in state : $state negotiating connection\n"; |
|
$returnstatus = "error"; |
|
$error = 1; |
|
} else { |
|
my $status; |
|
$status = $wantread ? $connection->Readable : $connection->Writable; |
|
if ($status != 0) { |
|
print "Error: I/O failed in state : $state negotiating connection\n"; |
|
$returnstatus = "error"; |
|
$error = 1; |
|
} |
|
} |
|
} |
|
|
|
|
|
return $returnstatus; |
|
} |
|
# |
|
# Perform a transaction with the remote lond. |
|
# Paramters: |
|
# connection - the connection object that represents |
|
# a LondConnection to the remote lond. |
|
# command - The request to send to the remote system. |
|
# Returns: |
|
# The 'reaction' of the lond to this command. |
|
# However if the connection to lond is lost during the transaction |
|
# or some other error occurs, the text "error:con_lost" is returned. |
|
# |
|
sub PerformTransaction { |
|
my $connection = shift; |
|
my $command = shift; |
|
my $retval; # What we'll returnl. |
|
|
|
# Set up the connection to do the transaction then |
|
# do the I/O until idle or error. |
|
# |
|
$connection->InitiateTransaction($command); |
|
my $error = 0; |
|
my $Socket = $connection->GetSocket; |
|
my $state; |
|
|
|
while (($connection->GetState ne "Idle") && (!$error)) { |
|
# |
|
# Wait for the socket to get into the appropriate state: |
|
# |
|
my $wantread = $connection->WantReadable; |
|
my $poll = new IO::Poll; |
|
$poll->mask($Socket => $wantread ? POLLIN : POLLOUT); |
|
$poll->poll($TransitionTimeout); |
|
my $done = $poll->handles(); |
|
if(scalar($done) == 0) { # Timeout!!! |
|
print "Error: Timeout in state : $state negotiating connection\n"; |
|
$retval = "error"; |
|
$error = 1; |
|
} else { |
|
my $status; |
|
$status = $wantread ? $connection->Readable : $connection->Writable; |
|
if ($status != 0) { |
|
print "Error: I/O failed in state : $state negotiating connection\n"; |
|
$retval = "error"; |
|
$error = 1; |
|
} |
|
} |
|
} |
|
# |
|
# Fetch the reply from the transaction |
|
# |
|
if(! $error) { |
|
$retval = $connection->GetReply; |
|
} |
|
|
|
return $retval; |
|
} |
|
# |
|
# Performs a transaction direct to a remote lond. |
# Parameter: |
# Parameter: |
# cmd - The text of the request. |
# cmd - The text of the request. |
# host - The host to which the request ultimately goes. |
# host - The host to which the request ultimately goes. |
Line 160 USAGE
|
Line 261 USAGE
|
# lond/lonc etc. |
# lond/lonc etc. |
# |
# |
sub subreply { |
sub subreply { |
my ($cmd,$server)=@_; |
my $cmd = shift; |
my $peerfile="$perlvar{'lonSockDir'}/$server"; |
my $host = shift; |
my $client=IO::Socket::UNIX->new(Peer =>"$peerfile", |
|
Type => SOCK_STREAM, |
|
Timeout => 10) |
my $connection = MakeLondConnection($host); |
or return "con_lost"; |
if ($connection eq undef) { |
print $client "$cmd\n"; |
return "Connect Failed"; |
my $answer=<$client>; |
} |
if (!$answer) { $answer="con_lost"; } |
my $reply = NegotiateStartup($connection); |
chomp($answer); |
if($reply ne "ok") { |
return $answer; |
return "connection negotiation failed"; |
|
} |
|
print "Connection negotiated\n"; |
|
my $reply = PerformTransaction($connection, $cmd); |
|
return $reply; |
|
|
|
|
|
# my ($cmd,$server)=@_; |
|
# my $peerfile="$perlvar{'lonSockDir'}/$server"; |
|
# my $client=IO::Socket::UNIX->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 <<< |
# >>> BUGBUG <<< |
# |
# |
Line 196 sub subreply {
|
Line 314 sub subreply {
|
# returns an empty list if the parse fails. |
# returns an empty list if the parse fails. |
# |
# |
|
|
|
|
sub ParseArgs { |
sub ParseArgs { |
my $pushing = ''; |
my $pushing = ''; |
my $reinitting = ''; |
my $reinitting = ''; |
|
|
if(!GetOptions('push=s' => \$pushing, |
if(!GetOptions('push=s' => \$pushing, |
'reinit=s' => \$reinitting)) { |
'reinit=s' => \$reinitting, |
|
'myname=s' => \$MyHost, |
|
'hosts=s' => \$ForeignHostTab)) { |
|
return (); |
|
} |
|
# The --myname and --hosts switch must have values and |
|
# most both appear if either appears: |
|
|
|
if(($MyHost ne "") && ($ForeignHostTab eq "")) { |
|
return (); |
|
} |
|
if(($ForeignHostTab ne "") && ($MyHost eq "")) { |
return (); |
return (); |
} |
} |
|
|
Line 214 sub ParseArgs {
|
Line 344 sub ParseArgs {
|
|
|
if($pushing ne '') { |
if($pushing ne '') { |
|
|
# --push takes in addition a table, and a host: |
# --push takes in addition a table, and an optional host: |
# |
# |
if($paramcount != 2) { |
if(($paramcount != 2) && ($paramcount != 1)) { |
return (); # Invalid parameter count. |
return (); # Invalid parameter count. |
} |
} |
if($command ne '') { |
if($command ne '') { |
Line 230 sub ParseArgs {
|
Line 360 sub ParseArgs {
|
|
|
if ($reinitting ne '') { |
if ($reinitting ne '') { |
|
|
# --reinit takes in addition just a host name |
# --reinit takes in addition just an optional host name |
|
|
if($paramcount != 1) { |
if($paramcount > 1) { |
return (); |
return (); |
} |
} |
if($command ne '') { |
if($command ne '') { |
Line 254 sub ParseArgs {
|
Line 384 sub ParseArgs {
|
return @result; |
return @result; |
} |
} |
# |
# |
# Read the loncapa configuration stuff. |
# Read the loncapa configuration stuff. If ForeignHostTab is empty, |
|
# assume we are part of a loncapa cluster and read the hosts.tab |
|
# file from the config directory. Otherwise, ForeignHossTab |
|
# is the name of an alternate configuration file to read in |
|
# standalone mode. |
# |
# |
sub ReadConfig { |
sub ReadConfig { |
my $perlvarref = LONCAPA::Configuration::read_conf('loncapa.conf'); |
|
%perlvar = %{$perlvarref}; |
|
my $hoststab = LONCAPA::Configuration::read_hosts( |
|
"$perlvar{'lonTabDir'}/hosts.tab"); |
|
%hostshash = %{$hoststab}; |
|
|
|
|
if($ForeignHostTab eq "") { |
|
my $perlvarref = LondConnection::read_conf('loncapa.conf'); |
|
%perlvar = %{$perlvarref}; |
|
my $hoststab = LondConnection::read_hosts( |
|
"$perlvar{'lonTabDir'}/hosts.tab"); |
|
%hostshash = %{$hoststab}; |
|
$MyHost = $perlvar{lonHostID}; # Set hostname from vars. |
|
$ServerPort = $perlvar{londPort}; |
|
} else { |
|
|
|
LondConnection::ReadForeignConfig($MyHost, $ForeignHostTab); |
|
my $hoststab = LondConnection::read_hosts($ForeignHostTab); # we need to know too. |
|
%hostshash = %{$hoststab}; |
|
$ServerPort = $DefaultServerPort; |
|
} |
|
|
} |
} |
# |
# |
# Determine if the target host is valid. |
# Determine if the target host is valid. |
Line 278 sub ReadConfig {
|
Line 423 sub ReadConfig {
|
sub ValidHost { |
sub ValidHost { |
my $host = shift; |
my $host = shift; |
|
|
ReadConfig; |
|
|
|
return defined $hostshash{$host}; |
return defined $hostshash{$host}; |
|
|
Line 374 sub PushFile {
|
Line 518 sub PushFile {
|
|
|
if( ($tablename eq "host") || |
if( ($tablename eq "host") || |
($tablename eq "domain")) { |
($tablename eq "domain")) { |
|
print("Pushing $tablename to $host\n"); |
Transact($host, "pushfile:$tablename",\@table); |
Transact($host, "pushfile:$tablename",\@table); |
} else { |
} else { |
die "EINVAL - Invalid parameter. tablename: $tablename must be host or domain"; |
die "EINVAL - Invalid parameter. tablename: $tablename must be host or domain"; |
Line 407 sub ReinitProcess {
|
Line 552 sub ReinitProcess {
|
|
|
if(($process eq "lonc") || |
if(($process eq "lonc") || |
($process eq "lond")) { |
($process eq "lond")) { |
|
print("Reinitializing $process in $host\n"); |
Transact($host, "reinit:$process"); |
Transact($host, "reinit:$process"); |
} else { |
} else { |
die "EINVAL -Invalid parameter. Process $process must be lonc or lond"; |
die "EINVAL -Invalid parameter. Process $process must be lonc or lond"; |
Line 414 sub ReinitProcess {
|
Line 560 sub ReinitProcess {
|
} |
} |
#--------------------------- Entry point: -------------------------- |
#--------------------------- Entry point: -------------------------- |
|
|
|
|
|
|
# Parse the parameters |
# Parse the parameters |
# If command parsing failed, then print usage: |
# If command parsing failed, then print usage: |
|
|
Line 431 if ($EUID != 0) {
|
Line 579 if ($EUID != 0) {
|
die "ENOPRIV - No privilege for requested operation" |
die "ENOPRIV - No privilege for requested operation" |
} |
} |
|
|
|
# |
|
# Read the configuration file. |
|
# |
|
|
|
ReadConfig; # Read the configuration info (incl.hosts). |
|
|
# Based on the operation requested invoke the appropriate function: |
# Based on the operation requested invoke the appropriate function: |
|
|
Line 440 if($operation eq "push") { # push table
|
Line 593 if($operation eq "push") { # push table
|
my $tablename = shift @params; |
my $tablename = shift @params; |
my $tablefile = shift @params; |
my $tablefile = shift @params; |
my $host = shift @params; |
my $host = shift @params; |
PushFile($tablename, $tablefile, $host); |
if($host) { |
|
PushFile($tablename, $tablefile, $host); |
|
} else { # Push to whole cluster. |
|
foreach my $host (keys %hostshash) { |
|
PushFile($tablename, $tablefile, $host); |
|
} |
|
} |
|
|
} elsif($operation eq "reinit") { # reinit processname host. |
} elsif($operation eq "reinit") { # reinit processname host. |
my $process = shift @params; |
my $process = shift @params; |
my $host = shift @params; |
my $host = shift @params; |
ReinitProcess($process, $host); |
if ($host) { |
} |
ReinitProcess($process, $host); |
|
} else { # Reinit whole cluster. |
|
foreach my $host (keys %hostshash) { |
|
ReinitProcess($process,$host); |
|
} |
|
} |
|
} |
else { |
else { |
Usage; |
Usage; |
} |
} |