453 lines
14 KiB
Perl
453 lines
14 KiB
Perl
#!/usr/bin/env perl
|
|
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
|
|
package xCAT::Zone;
|
|
|
|
BEGIN
|
|
{
|
|
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
|
|
}
|
|
|
|
# if AIX - make sure we include perl 5.8.2 in INC path.
|
|
# Needed to find perl dependencies shipped in deps tarball.
|
|
if ($^O =~ /^aix/i) {
|
|
unshift(@INC, qw(/usr/opt/perl5/lib/5.8.2/aix-thread-multi /usr/opt/perl5/lib/5.8.2 /usr/opt/perl5/lib/site_perl/5.8.2/aix-thread-multi /usr/opt/perl5/lib/site_perl/5.8.2));
|
|
}
|
|
|
|
use lib "$::XCATROOT/lib/perl";
|
|
# do not put a use or require for xCAT::Table here. Add to each new routine
|
|
# needing it to avoid reprocessing of user tables ( ExtTab.pm) for each command call
|
|
use POSIX qw(ceil);
|
|
use File::Path;
|
|
use Socket;
|
|
use strict;
|
|
use Symbol;
|
|
use warnings "all";
|
|
|
|
#--------------------------------------------------------------------------------
|
|
|
|
=head1 xCAT::Zone
|
|
|
|
=head2 Package Description
|
|
|
|
This program module file, is a set of Zone utilities used by xCAT *zone commands.
|
|
|
|
=cut
|
|
|
|
|
|
#--------------------------------------------------------------------------------
|
|
|
|
=head3 genSSHRootKeys
|
|
Arguments:
|
|
callback for error messages
|
|
directory in which to put the ssh RSA keys
|
|
zonename
|
|
rsa private key to use for generation ( optional)
|
|
Returns:
|
|
Error: 1 - key generation failure.
|
|
Example:
|
|
$rc =xCAT::Zone->genSSHRootKeys($callback,$keydir,$rsakey);
|
|
=cut
|
|
|
|
#--------------------------------------------------------------------------------
|
|
sub genSSHRootKeys
|
|
{
|
|
my ($class, $callback, $keydir,$zonename,$rsakey) = @_;
|
|
|
|
#
|
|
# create /keydir if needed
|
|
#
|
|
if (!-d $keydir)
|
|
{
|
|
my $cmd = "/bin/mkdir -m 700 -p $keydir";
|
|
my $output = xCAT::Utils->runcmd("$cmd", 0);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp = {};
|
|
$rsp->{error}->[0] =
|
|
"Could not create $keydir directory";
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
return 1;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
#need to gen a new rsa key for root for the zone
|
|
my $pubfile = "$keydir/id_rsa.pub";
|
|
my $pvtfile = "$keydir/id_rsa";
|
|
|
|
# if exists, remove the old files
|
|
if (-r $pubfile)
|
|
{
|
|
|
|
my $cmd = "/bin/rm $keydir/id_rsa*";
|
|
my $output = xCAT::Utils->runcmd("$cmd", 0);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp = {};
|
|
$rsp->{error}->[0] = "Could not remove id_rsa files from $keydir directory.";
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
# gen new RSA keys
|
|
my $cmd;
|
|
my $output;
|
|
# if private key was input use it
|
|
if (defined ($rsakey)) {
|
|
$cmd="/usr/bin/ssh-keygen -y -f $rsakey > $pubfile";
|
|
$output = xCAT::Utils->runcmd("$cmd", 0);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp = {};
|
|
$rsp->{error}->[0] = "Could not generate $pubfile from $rsakey";
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
return 1;
|
|
}
|
|
# now copy the private key into the directory
|
|
$cmd="cp $rsakey $keydir";
|
|
$output = xCAT::Utils->runcmd("$cmd", 0);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp = {};
|
|
$rsp->{error}->[0] = "Could not run $cmd";
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
return 1;
|
|
}
|
|
} else { # generate all new keys
|
|
$cmd = "/usr/bin/ssh-keygen -t rsa -q -b 2048 -N '' -f $pvtfile";
|
|
$output = xCAT::Utils->runcmd("$cmd", 0);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp = {};
|
|
$rsp->{error}->[0] = "Could not generate $pubfile";
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
return 1;
|
|
}
|
|
}
|
|
#make sure permissions are correct
|
|
$cmd = "chmod 644 $pubfile;chown root $pubfile";
|
|
$output = xCAT::Utils->runcmd("$cmd", 0);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp = {};
|
|
$rsp->{error}->[0] = "Could set permission and owner on $pubfile";
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
return 1;
|
|
}
|
|
}
|
|
#--------------------------------------------------------------------------------
|
|
|
|
=head3 getdefaultzone
|
|
Arguments:
|
|
None
|
|
Returns:
|
|
Name of the current default zone from the zone table
|
|
Example:
|
|
my $defaultzone =xCAT::Zone->getdefaultzone($callback);
|
|
=cut
|
|
|
|
#--------------------------------------------------------------------------------
|
|
sub getdefaultzone
|
|
{
|
|
my ($class, $callback) = @_;
|
|
my $defaultzone;
|
|
# read all the zone table and find the defaultzone, if it exists
|
|
my $tab = xCAT::Table->new("zone");
|
|
if ($tab){
|
|
my @zones = $tab->getAllAttribs('zonename','defaultzone');
|
|
foreach my $zone (@zones) {
|
|
# Look for the defaultzone=yes/1 entry
|
|
if ((defined($zone->{defaultzone})) &&
|
|
(($zone->{defaultzone} =~ /^yes$/i )
|
|
|| ($zone->{defaultzone} eq "1"))) {
|
|
$defaultzone = $zone->{zonename};
|
|
}
|
|
$tab->close();
|
|
}
|
|
} else {
|
|
my $rsp = {};
|
|
$rsp->{error}->[0] =
|
|
"Error reading the zone table. ";
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
|
|
}
|
|
return $defaultzone;
|
|
}
|
|
#--------------------------------------------------------------------------------
|
|
|
|
=head3 iszonedefined
|
|
Arguments:
|
|
zonename
|
|
Returns:
|
|
1 if the zone is already in the zone table.
|
|
Example:
|
|
xCAT::Zone->iszonedefined($zonename);
|
|
=cut
|
|
|
|
#--------------------------------------------------------------------------------
|
|
sub iszonedefined
|
|
{
|
|
my ($class,$zonename) = @_;
|
|
# checks the zone table to see if input zonename already in the table
|
|
my $tab = xCAT::Table->new("zone");
|
|
$tab->close();
|
|
my $zonehash = $tab->getAttribs({zonename => $zonename},'sshkeydir');
|
|
if ( keys %$zonehash) {
|
|
return 1;
|
|
}else{
|
|
return 0;
|
|
}
|
|
}
|
|
#--------------------------------------------------------------------------------
|
|
|
|
=head3 getzonekeydir
|
|
Arguments:
|
|
zonename
|
|
Returns:
|
|
path to the root ssh keys for the zone /etc/xcat/sshkeys/<zonename>/.ssh
|
|
1 - zone not defined
|
|
Example:
|
|
xCAT::Zone->getzonekeydir($zonename);
|
|
=cut
|
|
|
|
#--------------------------------------------------------------------------------
|
|
sub getzonekeydir
|
|
{
|
|
my ($class,$zonename) = @_;
|
|
my $tab = xCAT::Table->new("zone");
|
|
$tab->close();
|
|
my $zonehash = $tab->getAttribs({zonename => $zonename},'sshkeydir');
|
|
if ( keys %$zonehash) {
|
|
my $zonesshkeydir=$zonehash->{sshkeydir};
|
|
return $zonesshkeydir;
|
|
}else{
|
|
return 1; # this is a bad error zone not defined
|
|
}
|
|
}
|
|
#--------------------------------------------------------------------------------
|
|
|
|
=head3 getmyzonename
|
|
Arguments:
|
|
$node -one nodename
|
|
Returns:
|
|
$zonename
|
|
Example:
|
|
my $zonename=xCAT::Zone->getmyzonename($node);
|
|
=cut
|
|
|
|
#--------------------------------------------------------------------------------
|
|
sub getmyzonename
|
|
{
|
|
my ($class,$node,$callback) = @_;
|
|
my @node;
|
|
push @node,$node;
|
|
my $zonename;
|
|
my $nodelisttab = xCAT::Table->new("nodelist");
|
|
my $nodehash = $nodelisttab->getNodesAttribs(\@node, ['zonename']);
|
|
$nodelisttab->close();
|
|
if ( defined ($nodehash->{$node}->[0]->{zonename})) { # it was defined in the nodelist table
|
|
$zonename=$nodehash->{$node}->[0]->{zonename};
|
|
} else { # get the default zone
|
|
$zonename =xCAT::Zone->getdefaultzone($callback);
|
|
}
|
|
return $zonename;
|
|
}
|
|
#--------------------------------------------------------------------------------
|
|
|
|
=head3 enableSSHbetweennodes
|
|
Arguments:
|
|
zonename
|
|
Returns:
|
|
1 if the sshbetweennodes attribute is yes/1 or undefined
|
|
0 if the sshbetweennodes attribute is no/0
|
|
Example:
|
|
xCAT::Zone->enableSSHbetweennodes($zonename);
|
|
=cut
|
|
|
|
#--------------------------------------------------------------------------------
|
|
sub enableSSHbetweennodes
|
|
{
|
|
my ($class,$node,$callback) = @_;
|
|
# finds the zone of the node
|
|
my $enablessh = 1; # default
|
|
my $zonename=xCAT::Zone->getmyzonename($node);
|
|
# reads the zone table
|
|
my $tab = xCAT::Table->new("zone");
|
|
$tab->close();
|
|
# read both keys, want to know zone is in the zone table. If sshkeydir is not there
|
|
# it is either missing or invalid anyway
|
|
my $zonehash = $tab->getAttribs({zonename => $zonename},'sshbetweennodes','sshkeydir');
|
|
if (! ( keys %$zonehash)) {
|
|
my $rsp = {};
|
|
$rsp->{error}->[0] =
|
|
"$node has a zonename: $zonename that is not define in the zone table. Remove the zonename from the node, or create the zone using mkzone. The generated mypostscript may not reflect the correct setting for ENABLESSHBETWEENNODES";
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
return $enablessh;
|
|
}
|
|
my $sshbetweennodes=$zonehash->{sshbetweennodes};
|
|
if (defined ($sshbetweennodes)) {
|
|
if (($sshbetweennodes =~ /^no$/i) || ($sshbetweennodes eq "0")) {
|
|
$enablessh = 0;
|
|
} else {
|
|
$enablessh = 1;
|
|
}
|
|
} else { # not defined default yes
|
|
$enablessh = 1 ; # default
|
|
}
|
|
return $enablessh;
|
|
}
|
|
#--------------------------------------------------------------------------------
|
|
|
|
=head3 usingzones
|
|
Arguments:
|
|
none
|
|
Returns:
|
|
1 if the zone table is not empty
|
|
0 if empty
|
|
Example:
|
|
xCAT::Zone->usingzones;
|
|
=cut
|
|
|
|
#--------------------------------------------------------------------------------
|
|
sub usingzones
|
|
{
|
|
my ($class) = @_;
|
|
# reads the zonetable
|
|
my $tab = xCAT::Table->new("zone");
|
|
my @zone = $tab->getAllAttribs('zonename');
|
|
$tab->close();
|
|
if (@zone) {
|
|
return 1;
|
|
}else{
|
|
return 0;
|
|
}
|
|
}
|
|
#--------------------------------------------------------------------------------
|
|
|
|
=head3 getzoneinfo
|
|
Arguments:
|
|
callback
|
|
An array of nodes
|
|
Returns:
|
|
Hash array by zonename point to the nodes in that zonename and sshkeydir
|
|
<zonename1> -> {nodelist} -> array of nodes in the zone
|
|
-> {sshkeydir} -> directory containing ssh RSA keys
|
|
-> {defaultzone} -> is it the default zone
|
|
Example:
|
|
my %zonehash =xCAT::Zone->getzoneinfo($callback,@nodearray);
|
|
Rules:
|
|
If the nodes nodelist.zonename attribute is a zonename, it is assigned to that zone
|
|
If the nodes nodelist.zonename attribute is undefined:
|
|
If there is a defaultzone in the zone table, the node is assigned to that zone
|
|
If there is no defaultzone in the zone table, the node is assigned to the ~.ssh keydir
|
|
$::GETZONEINFO_RC
|
|
0 = good return
|
|
1 = error occured
|
|
=cut
|
|
|
|
#--------------------------------------------------------------------------------
|
|
sub getzoneinfo
|
|
{
|
|
my ($class, $callback,$nodes) = @_;
|
|
$::GETZONEINFO_RC=0;
|
|
my $zonehash;
|
|
my $defaultzone;
|
|
# read all the zone table
|
|
my $zonetab = xCAT::Table->new("zone");
|
|
my @zones;
|
|
if ($zonetab){
|
|
@zones = $zonetab->getAllAttribs('zonename','sshkeydir','sshbetweennodes','defaultzone');
|
|
$zonetab->close();
|
|
if (@zones) {
|
|
foreach my $zone (@zones) {
|
|
my $zonename=$zone->{zonename};
|
|
$zonehash->{$zonename}->{sshkeydir}= $zone->{sshkeydir};
|
|
$zonehash->{$zonename}->{defaultzone}= $zone->{defaultzone};
|
|
$zonehash->{$zonename}->{sshbetweennodes}= $zone->{sshbetweennodes};
|
|
# find the defaultzone
|
|
if ((defined($zone->{defaultzone})) &&
|
|
(($zone->{defaultzone} =~ /^yes$/i )
|
|
|| ($zone->{defaultzone} eq "1"))) {
|
|
$defaultzone = $zone->{zonename};
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
my $rsp = {};
|
|
$rsp->{error}->[0] =
|
|
"Error reading the zone table. ";
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
$::GETZONEINFO_RC =1;
|
|
return;
|
|
|
|
}
|
|
my $nodelisttab = xCAT::Table->new("nodelist");
|
|
my $nodehash = $nodelisttab->getNodesAttribs(\@$nodes, ['zonename']);
|
|
# for each of the nodes, look up it's zone name and assign to the zonehash
|
|
# If the nodes nodelist.zonename attribute is a zonename, it is assigned to that zone
|
|
# If the nodes nodelist.zonename attribute is undefined:
|
|
# If there is a defaultzone in the zone table, the node is assigned to that zone
|
|
# If there is no defaultzone error out
|
|
|
|
|
|
foreach my $node (@$nodes) {
|
|
my $zonename;
|
|
$zonename=$nodehash->{$node}->[0]->{zonename};
|
|
if (defined($zonename)) { # zonename explicitly defined in nodelist.zonename
|
|
# check to see if defined in the zone table
|
|
unless ( xCAT::Zone->iszonedefined($zonename)) {
|
|
my $rsp = {};
|
|
$rsp->{error}->[0] =
|
|
"$node has a zonename: $zonename that is not define in the zone table. Remove the zonename from the node, or create the zone using mkzone.";
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
$::GETZONEINFO_RC =1;
|
|
return;
|
|
}
|
|
push @{$zonehash->{$zonename}->{nodes}},$node;
|
|
} else { # no explict zonename
|
|
if (defined ($defaultzone)) { # there is a default zone in the zone table, use it
|
|
push @{$zonehash->{$defaultzone}->{nodes}},$node;
|
|
} else { # if no default, this is an error
|
|
my $rsp = {};
|
|
$rsp->{error}->[0] =
|
|
"There is no default zone defined in the zone table. There must be exactly one default zone. ";
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
$::GETZONEINFO_RC =1;
|
|
return;
|
|
|
|
}
|
|
}
|
|
}
|
|
return $zonehash;
|
|
}
|
|
#--------------------------------------------------------------------------------
|
|
|
|
=head3 getnodesinzone
|
|
Arguments:
|
|
callback
|
|
zonename
|
|
Returns:
|
|
Array of nodes
|
|
Example:
|
|
my @nodes =xCAT::Zone->getnodesinzone($callback,$zonename);
|
|
=cut
|
|
|
|
#--------------------------------------------------------------------------------
|
|
sub getnodesinzone
|
|
{
|
|
my ($class, $callback,$zonename) = @_;
|
|
my @nodes;
|
|
my $nodelisttab = xCAT::Table->new("nodelist");
|
|
my @nodelist=$nodelisttab->getAllAttribs('node','zonename');
|
|
# build the array of nodes in this zone
|
|
foreach my $nodename (@nodelist) {
|
|
if ((defined($nodename->{'zonename'})) && ($nodename->{'zonename'} eq $zonename)) {
|
|
push @nodes,$nodename->{'node'};
|
|
}
|
|
}
|
|
return @nodes;
|
|
}
|
|
1;
|