mirror of
https://github.com/xcat2/xcat-core.git
synced 2025-09-05 17:58:14 +00:00
* To fix issue that lose activation success log * update onie doc to add rspconfig sshcfg command (#5539) * fix osarch missing from copycds (#5543) * Modify release information for 2.14.3 release * update goconserver quickstart document * Enhancement for using site cache in plugin (#5535) * site cache when run plugin does not work very well - using cache from plugin when getNodesAttribs/getNodeAttribs (pass it into DB process from plugin process) - Site cache is a whole hash, so to use cache when by the hash is there, instead of the specified key is there. It is because that there might be no key defined in site table. * with XCATBYPASS, to populate site hash before scan_plugins. Then only 1 query for site table to do whole things. * cache site when init plugins on service nodes * missing to comment the old codes query from xCAT DB process
2130 lines
60 KiB
Perl
Executable File
2130 lines
60 KiB
Perl
Executable File
#!/usr/bin/env perl
|
|
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
|
|
package xCAT::TableUtils;
|
|
|
|
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";
|
|
use strict;
|
|
require xCAT::Table;
|
|
require xCAT::Zone;
|
|
use File::Path;
|
|
|
|
#-----------------------------------------------------------------------
|
|
|
|
=head3
|
|
list_all_nodes
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
an array of all define nodes from the nodelist table
|
|
Globals:
|
|
none
|
|
Error:
|
|
undef
|
|
Example:
|
|
@nodes=xCAT::TableUtils->list_all_nodes;
|
|
Comments:
|
|
none
|
|
|
|
=cut
|
|
|
|
#------------------------------------------------------------------------
|
|
sub list_all_nodes
|
|
{
|
|
my @nodes;
|
|
my @nodelist;
|
|
my $nodelisttab;
|
|
if ($nodelisttab = xCAT::Table->new("nodelist"))
|
|
{
|
|
my @attribs = ("node");
|
|
@nodes = $nodelisttab->getAllAttribs(@attribs);
|
|
foreach my $node (@nodes)
|
|
{
|
|
push @nodelist, $node->{node};
|
|
}
|
|
}
|
|
else
|
|
{
|
|
xCAT::MsgUtils->message("E", " Could not read the nodelist table\n");
|
|
}
|
|
return @nodelist;
|
|
}
|
|
|
|
#-----------------------------------------------------------------------
|
|
|
|
=head3
|
|
list_all_nodegroups
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
an array of all define node groups from the nodelist and nodegroup
|
|
table
|
|
Globals:
|
|
none
|
|
Error:
|
|
undef
|
|
Example:
|
|
@nodegrps=xCAT::TableUtils->list_all_nodegroups;
|
|
Comments:
|
|
none
|
|
|
|
=cut
|
|
|
|
#------------------------------------------------------------------------
|
|
sub list_all_node_groups
|
|
{
|
|
my @grouplist;
|
|
my @grouplist2;
|
|
my @distinctgroups;
|
|
my $nodelisttab;
|
|
if ($nodelisttab = xCAT::Table->new("nodelist"))
|
|
{
|
|
my @attribs = ("groups");
|
|
@grouplist = $nodelisttab->getAllAttribs(@attribs);
|
|
|
|
# build a distinct list of unique group names
|
|
foreach my $group (@grouplist)
|
|
{
|
|
my $gnames = $group->{groups};
|
|
my @groupnames = split ",", $gnames;
|
|
foreach my $groupname (@groupnames)
|
|
{
|
|
if (!grep(/^$groupname$/, @distinctgroups))
|
|
{ # not already in list
|
|
push @distinctgroups, $groupname;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
xCAT::MsgUtils->message("E", " Could not read the nodelist table\n");
|
|
}
|
|
$nodelisttab->close;
|
|
|
|
# now read the nodegroup table
|
|
if ($nodelisttab = xCAT::Table->new("nodegroup"))
|
|
{
|
|
my @attribs = ("groupname");
|
|
@grouplist = $nodelisttab->getAllAttribs(@attribs);
|
|
|
|
# build a distinct list of unique group names
|
|
foreach my $group (@grouplist)
|
|
{
|
|
my $groupname = $group->{groupname};
|
|
if (!grep(/^$groupname$/, @distinctgroups))
|
|
{ # not already in list
|
|
push @distinctgroups, $groupname;
|
|
}
|
|
}
|
|
$nodelisttab->close;
|
|
}
|
|
else
|
|
{
|
|
xCAT::MsgUtils->message("E", " Could not read the nodegroup table\n");
|
|
}
|
|
|
|
return @distinctgroups;
|
|
}
|
|
|
|
#--------------------------------------------------------------------------------
|
|
|
|
=head3 bldnonrootSSHFiles
|
|
|
|
Builds authorized_keyfiles for the non-root id
|
|
It must not only contain the public keys for the non-root id
|
|
but also the public keys for root
|
|
|
|
Arguments:
|
|
from_userid -current id running xdsh from the command line
|
|
Returns:
|
|
|
|
Globals:
|
|
$::CALLBACK
|
|
Error:
|
|
|
|
Example:
|
|
xCAT::TableUtils->bldnonrootSSHFiles;
|
|
|
|
Comments:
|
|
none
|
|
|
|
=cut
|
|
|
|
#--------------------------------------------------------------------------------
|
|
|
|
sub bldnonrootSSHFiles
|
|
{
|
|
my ($class, $from_userid) = @_;
|
|
my ($cmd, $rc);
|
|
my $rsp = {};
|
|
if ($::VERBOSE)
|
|
{
|
|
$rsp->{data}->[0] = "Building SSH Keys for $from_userid";
|
|
xCAT::MsgUtils->message("I", $rsp, $::CALLBACK);
|
|
}
|
|
my $home = xCAT::Utils->getHomeDir($from_userid);
|
|
|
|
# Handle non-root userid may not be in /etc/passwd maybe LDAP
|
|
if (!$home) {
|
|
$home = `su - $from_userid -c pwd`;
|
|
chop $home;
|
|
}
|
|
my $roothome = xCAT::Utils->getHomeDir("root");
|
|
if (xCAT::Utils->isMN()) { # if on Management Node
|
|
if (!(-e "$home/.ssh/id_rsa.pub"))
|
|
{
|
|
$rsp->{data}->[0] = "$home/.ssh/id_rsa.pub does not exist!";
|
|
xCAT::MsgUtils->message("I", $rsp, $::CALLBACK);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
# make tmp directory to hold authorized_keys for node transfer
|
|
if (!(-e "$home/.ssh/tmp")) {
|
|
$cmd = " mkdir $home/.ssh/tmp";
|
|
xCAT::Utils->runcmd($cmd, 0);
|
|
$rsp = {};
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
$rsp->{data}->[0] = "$cmd failed.\n";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
|
|
return (1);
|
|
|
|
}
|
|
}
|
|
|
|
# create authorized_key file in tmp directory for transfer
|
|
if (xCAT::Utils->isMN()) { # if on Management Node
|
|
$cmd = " cp $home/.ssh/id_rsa.pub $home/.ssh/tmp/authorized_keys";
|
|
} else { # SN
|
|
if(!(-e "$home/.ssh/authorized_keys")){
|
|
$rsp->{data}->[0] = "$home/.ssh/authorized_keys does not exist, make sure you have setup the ssh-keys on this service node.\n";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
|
|
return (1);
|
|
}
|
|
$cmd = " cp $home/.ssh/authorized_keys $home/.ssh/tmp/authorized_keys";
|
|
}
|
|
xCAT::Utils->runcmd($cmd, 0);
|
|
$rsp = {};
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
$rsp->{data}->[0] = "$cmd failed.\n";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
|
|
return (1);
|
|
|
|
}
|
|
else
|
|
{
|
|
chmod 0600, "$home/.ssh/tmp/authorized_keys";
|
|
if ($::VERBOSE)
|
|
{
|
|
$rsp->{data}->[0] = "$cmd succeeded.\n";
|
|
xCAT::MsgUtils->message("I", $rsp, $::CALLBACK);
|
|
}
|
|
}
|
|
if (xCAT::Utils->isMN()) { # if on Management Node
|
|
# if cannot access, warn and continue
|
|
$rsp = {};
|
|
$cmd = "cat $roothome/.ssh/id_rsa.pub >> $home/.ssh/tmp/authorized_keys";
|
|
xCAT::Utils->runcmd($cmd, 0);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
$rsp->{data}->[0] = "Warning: Cannot give $from_userid root ssh authority. \n";
|
|
xCAT::MsgUtils->message("I", $rsp, $::CALLBACK);
|
|
|
|
}
|
|
else
|
|
{
|
|
if ($::VERBOSE)
|
|
{
|
|
$rsp->{data}->[0] = "$cmd succeeded.\n";
|
|
xCAT::MsgUtils->message("I", $rsp, $::CALLBACK);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return (0);
|
|
}
|
|
|
|
#--------------------------------------------------------------------------------
|
|
|
|
=head3 setupSSH
|
|
|
|
Generates if needed and Transfers the ssh keys
|
|
fOr a userid to setup ssh to the input nodes.
|
|
|
|
Arguments:
|
|
Array of nodes
|
|
Timeout for expect call (optional)
|
|
Returns:
|
|
|
|
Env Variables: $DSH_FROM_USERID, $DSH_TO_USERID, $DSH_REMOTE_PASSWORD
|
|
the ssh keys are transferred from the $DSH_FROM_USERID to the $DSH_TO_USERID
|
|
on the node(s). The DSH_REMOTE_PASSWORD and the DSH_FROM_USERID
|
|
must be obtained by
|
|
the calling script or from the xdsh client
|
|
|
|
Globals:
|
|
$::XCATROOT , $::CALLBACK
|
|
Error:
|
|
0=good, 1=error
|
|
Example:
|
|
xCAT::TableUtils->setupSSH(@target_nodes,$expecttimeout);
|
|
Comments:
|
|
Does not setup known_hosts. Assumes automatically
|
|
setup by SSH ( ssh config option StrictHostKeyChecking no should
|
|
be set in the ssh config file).
|
|
|
|
=cut
|
|
|
|
#--------------------------------------------------------------------------------
|
|
sub setupSSH
|
|
{
|
|
my ($class, $ref_nodes, $expecttimeout) = @_;
|
|
my @nodes = $ref_nodes;
|
|
my @badnodes = ();
|
|
my $n_str = $nodes[0];
|
|
my $SSHdir = xCAT::TableUtils->getInstallDir() . "/postscripts/_ssh";
|
|
if (!($ENV{'DSH_REMOTE_PASSWORD'}))
|
|
{
|
|
my $rsp = ();
|
|
$rsp->{data}->[0] =
|
|
"User password for the ssh key exchange has not been input. xdsh -K cannot complete.\n";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK, 1);
|
|
return;
|
|
|
|
}
|
|
|
|
# setup who the keys are coming from and who they are going to
|
|
my $from_userid;
|
|
my $to_userid;
|
|
if (!($ENV{'DSH_FROM_USERID'}))
|
|
{
|
|
my $rsp = ();
|
|
$rsp->{data}->[0] =
|
|
"DSH From Userid has not been input. xdsh -K cannot complete.\n";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK, 1);
|
|
return;
|
|
|
|
}
|
|
else
|
|
{
|
|
$from_userid = $ENV{'DSH_FROM_USERID'};
|
|
}
|
|
if (!($ENV{'DSH_TO_USERID'}))
|
|
{
|
|
my $rsp = ();
|
|
$rsp->{data}->[0] =
|
|
"DSH to Userid has not been input. xdsh -K cannot complete.\n";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK, 1);
|
|
return;
|
|
|
|
}
|
|
else
|
|
{
|
|
$to_userid = $ENV{'DSH_TO_USERID'};
|
|
}
|
|
|
|
|
|
#
|
|
# if we are running as root
|
|
# for non-root users, keys were generated in the xdsh client code
|
|
#
|
|
|
|
$::REMOTE_SHELL = "/usr/bin/ssh";
|
|
my $rsp = {};
|
|
|
|
|
|
# Get the home directory
|
|
my $home = xCAT::Utils->getHomeDir($from_userid);
|
|
unless($home){
|
|
$rsp->{data}->[0] = "Cannot get the home directory for user \"$from_userid\", please make sure \"$from_userid\" user exists!";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
|
|
return 1;
|
|
}
|
|
$ENV{'DSH_FROM_USERID_HOME'} = $home;
|
|
if ($from_userid eq "root")
|
|
{
|
|
# make the directory to hold keys to transfer to the nodes
|
|
if (!-d $SSHdir)
|
|
{
|
|
mkpath("$SSHdir", { mode => 0755 });
|
|
}
|
|
|
|
# generates new keys for root, if they do not already exist ~/.ssh
|
|
|
|
# nodes not used on this option but in there to preserve the interface
|
|
if($::VERBOSE){
|
|
$rsp->{data}->[0] = "Generating SSH keys for $from_userid.\n";
|
|
xCAT::MsgUtils->message("I", $rsp, $::CALLBACK);
|
|
}
|
|
my $rc =
|
|
xCAT::RemoteShellExp->remoteshellexp("k", $::CALLBACK, $::REMOTE_SHELL, $n_str, $expecttimeout);
|
|
if ($rc != 0) {
|
|
$rsp->{data}->[0] = "remoteshellexp failed generating keys.";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
|
|
}
|
|
}
|
|
# build the shell copy script, needed Perl not always there
|
|
# for root and non-root ids
|
|
if($::VERBOSE){
|
|
$rsp->{data}->[0] = "Creating helper script \"$home/.ssh/copy.sh\" to install the ssh key files, which will be sent and invoked to target node then.\n";
|
|
xCAT::MsgUtils->message("I", $rsp, $::CALLBACK);
|
|
}
|
|
|
|
|
|
unless(open(FILE, ">$home/.ssh/copy.sh"))
|
|
{
|
|
$rsp->{data}->[0] ="cannot create file $home/.ssh/copy.sh, please make sure the directory \"$home/.ssh\" exists and ssh keys have been setup on this node!\n";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
|
|
return 1;
|
|
}
|
|
print FILE "#!/bin/sh
|
|
umask 0077
|
|
home=`egrep \"^$to_userid:\" /etc/passwd | cut -f6 -d :`
|
|
if [ $home ]; then
|
|
dest_dir=\"\$home/.ssh\"
|
|
else
|
|
home=`su - root -c pwd`
|
|
dest_dir=\"\$home/.ssh\"
|
|
fi
|
|
mkdir -p \$dest_dir
|
|
cat /tmp/$to_userid/.ssh/authorized_keys >> \$home/.ssh/authorized_keys 2>&1
|
|
cat /tmp/$to_userid/.ssh/id_rsa.pub >> \$home/.ssh/authorized_keys 2>&1
|
|
rm -f \$home/.ssh/id_rsa 2>&1
|
|
cp /tmp/$to_userid/.ssh/id_rsa \$home/.ssh/id_rsa 2>&1
|
|
cp /tmp/$to_userid/.ssh/id_rsa.pub \$home/.ssh/id_rsa.pub 2>&1
|
|
chmod 0600 \$home/.ssh/id_* 2>&1
|
|
rm -f /tmp/$to_userid/.ssh/* 2>&1
|
|
rmdir \"/tmp/$to_userid/.ssh\"
|
|
rmdir \"/tmp/$to_userid\" \n";
|
|
|
|
close FILE;
|
|
chmod 0777, "$home/.ssh/copy.sh";
|
|
my $auth_key = 0;
|
|
my $auth_key2 = 0;
|
|
if ($from_userid eq "root")
|
|
{
|
|
# this will put the root/.ssh/id_rsa.pub key in the authorized keys file to put on the node
|
|
my $rc = xCAT::TableUtils->cpSSHFiles($SSHdir);
|
|
if ($rc != 0)
|
|
{ # error
|
|
$rsp->{data}->[0] = "Error running cpSSHFiles.\n";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
|
|
return 1;
|
|
|
|
}
|
|
if (xCAT::Utils->isMN()) { # if on Management Node
|
|
# copy the copy install file to the install directory, if from and
|
|
# to userid are root
|
|
if ($to_userid eq "root")
|
|
{
|
|
|
|
my $cmd = " cp $home/.ssh/copy.sh $SSHdir/copy.sh";
|
|
xCAT::Utils->runcmd($cmd, 0);
|
|
my $rsp = {};
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
$rsp->{data}->[0] = "$cmd failed.\n";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
|
|
return (1);
|
|
|
|
}
|
|
}
|
|
} # end is MN
|
|
}
|
|
else { # from_userid is not root
|
|
# build the authorized key files for non-root user
|
|
xCAT::TableUtils->bldnonrootSSHFiles($from_userid);
|
|
}
|
|
|
|
# send the keys
|
|
# For root user and not to devices only to nodes
|
|
if (($from_userid eq "root") && (!($ENV{'DEVICETYPE'}))) {
|
|
|
|
# Need to check if nodes are in a zone.
|
|
my @zones;
|
|
my $tab = xCAT::Table->new("zone");
|
|
if ($tab)
|
|
{
|
|
# if we have zones, need to send the zone keys to each node in the zone
|
|
my @attribs = ("zonename");
|
|
@zones = $tab->getAllAttribs(@attribs);
|
|
$tab->close();
|
|
} else {
|
|
$rsp->{data}->[0] = "Could not open zone table.\n";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
|
|
return 1;
|
|
}
|
|
|
|
# check for zones, key send is different if zones defined or not
|
|
|
|
if (@zones) { # we have zones defined
|
|
my $rc = xCAT::TableUtils->sendkeysTOzones($ref_nodes, $expecttimeout);
|
|
if ($rc != 0)
|
|
{
|
|
$rsp->{data}->[0] = "Error sending ssh keys to the zones.\n";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
|
|
exit 1;
|
|
|
|
}
|
|
} else { # no zones
|
|
|
|
# if no zone table defined, do it the old way , keys are in ~/.ssh
|
|
my $rc = xCAT::TableUtils->sendkeysNOzones($ref_nodes, $expecttimeout);
|
|
if ($rc != 0)
|
|
{
|
|
$rsp->{data}->[0] = "Error sending ssh keys to the nodes.\n";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
|
|
|
|
}
|
|
}
|
|
|
|
} else { # from user is not root or it is a device , always send private key
|
|
$ENV{'DSH_ENABLE_SSH'} = "YES";
|
|
my $rc = xCAT::RemoteShellExp->remoteshellexp("s", $::CALLBACK, "/usr/bin/ssh", $n_str, $expecttimeout);
|
|
if ($rc != 0)
|
|
{
|
|
$rsp->{data}->[0] = "remoteshellexp failed sending keys.";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
|
|
|
|
}
|
|
}
|
|
|
|
# must always check to see if worked, run test
|
|
my @testnodes = split(",", $nodes[0]);
|
|
foreach my $n (@testnodes)
|
|
{
|
|
my $rc =
|
|
xCAT::RemoteShellExp->remoteshellexp("t", $::CALLBACK, "/usr/bin/ssh", $n, $expecttimeout);
|
|
if ($rc != 0)
|
|
{
|
|
push @badnodes, $n;
|
|
}
|
|
}
|
|
|
|
if (@badnodes)
|
|
{
|
|
my $nstring = join ',', @badnodes;
|
|
$rsp->{data}->[0] =
|
|
"SSH setup failed for the following nodes: $nstring.";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
|
|
return @badnodes;
|
|
}
|
|
else
|
|
{
|
|
$rsp->{data}->[0] = "$::REMOTE_SHELL setup is complete.";
|
|
xCAT::MsgUtils->message("I", $rsp, $::CALLBACK);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#--------------------------------------------------------------------------------
|
|
|
|
=head3 sendkeysNOzones
|
|
|
|
Transfers the ssh keys
|
|
for the root id on the nodes no zones
|
|
key from ~/.ssh site.sshbetweennodes honored
|
|
|
|
|
|
Arguments:
|
|
Array of nodes
|
|
Timeout for expect call (optional)
|
|
Returns:
|
|
|
|
Env Variables: $DSH_FROM_USERID, $DSH_TO_USERID, $DSH_REMOTE_PASSWORD
|
|
the ssh keys are transferred from the $DSH_FROM_USERID to the $DSH_TO_USERID
|
|
on the node(s). The DSH_REMOTE_PASSWORD and the DSH_FROM_USERID
|
|
must be obtained by
|
|
the calling script or from the xdsh client
|
|
|
|
Globals:
|
|
$::XCATROOT , $::CALLBACK
|
|
Error:
|
|
0=good, 1=error
|
|
Example:
|
|
xCAT::TableUtils->sendkeysNOzones($ref_nodes,$expecttimeout);
|
|
Comments:
|
|
Does not setup known_hosts. Assumes automatically
|
|
setup by SSH ( ssh config option StrictHostKeyChecking no should
|
|
be set in the ssh config file).
|
|
|
|
=cut
|
|
|
|
#--------------------------------------------------------------------------------
|
|
sub sendkeysNOzones
|
|
{
|
|
my ($class, $ref_nodes, $expecttimeout) = @_;
|
|
my @nodes = $ref_nodes;
|
|
my $enablenodes;
|
|
my $disablenodes;
|
|
my $n_str = $nodes[0];
|
|
my @nodelist = split(",", $n_str);
|
|
my $rsp = ();
|
|
foreach my $n (@nodelist)
|
|
{
|
|
my $enablessh = xCAT::TableUtils->enablessh($n);
|
|
if ($enablessh == 1) {
|
|
$enablenodes .= $n;
|
|
$enablenodes .= ",";
|
|
} else {
|
|
$disablenodes .= $n;
|
|
$disablenodes .= ",";
|
|
}
|
|
|
|
}
|
|
if ($enablenodes) { # node on list to setup nodetonodessh
|
|
chop $enablenodes; # remove last comma
|
|
$ENV{'DSH_ENABLE_SSH'} = "YES";
|
|
|
|
# send the keys to the nodes
|
|
my $rc = xCAT::RemoteShellExp->remoteshellexp("s", $::CALLBACK, "/usr/bin/ssh", $enablenodes, $expecttimeout);
|
|
if ($rc != 0)
|
|
{
|
|
$rsp->{data}->[0] = "remoteshellexp failed sending keys to enablenodes.";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
|
|
|
|
}
|
|
}
|
|
if ($disablenodes) { # node on list to disable nodetonodessh
|
|
chop $disablenodes; # remove last comma
|
|
# send the keys to the nodes
|
|
my $rc = xCAT::RemoteShellExp->remoteshellexp("s", $::CALLBACK, "/usr/bin/ssh", $disablenodes, $expecttimeout);
|
|
if ($rc != 0)
|
|
{
|
|
$rsp->{data}->[0] = "remoteshellexp failed sending keys to disablenodes.";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
#--------------------------------------------------------------------------------
|
|
|
|
=head3 sendkeysTOzones
|
|
|
|
Transfers the ssh keys
|
|
for the root id on the nodes using the zone table.
|
|
If in a zone, then root ssh keys for the node will be taken from the zones ssh keys not ~/.ssh
|
|
zones are only supported on nodes that are not a service node.
|
|
Also for the call to RemoteShellExp, we must group the nodes that are in the same zone
|
|
|
|
|
|
Arguments:
|
|
Array of nodes
|
|
Timeout for expect call (optional)
|
|
Returns:
|
|
|
|
Env Variables: $DSH_FROM_USERID, $DSH_TO_USERID, $DSH_REMOTE_PASSWORD
|
|
the ssh keys are transferred from the $DSH_FROM_USERID to the $DSH_TO_USERID
|
|
on the node(s). The DSH_REMOTE_PASSWORD and the DSH_FROM_USERID
|
|
must be obtained by
|
|
the calling script or from the xdsh client
|
|
|
|
Globals:
|
|
$::XCATROOT , $::CALLBACK
|
|
Error:
|
|
0=good, 1=error
|
|
Example:
|
|
xCAT::TableUtils->sendkeysTOzones($ref_nodes,$expecttimeout);
|
|
Comments:
|
|
Does not setup known_hosts. Assumes automatically
|
|
setup by SSH ( ssh config option StrictHostKeyChecking no should
|
|
be set in the ssh config file).
|
|
|
|
=cut
|
|
|
|
#--------------------------------------------------------------------------------
|
|
sub sendkeysTOzones
|
|
{
|
|
my ($class, $ref_nodes, $expecttimeout) = @_;
|
|
my @nodes = $ref_nodes;
|
|
my $n_str = $nodes[0];
|
|
@nodes = split(",", $n_str);
|
|
my $rsp = ();
|
|
my $cmd;
|
|
my $roothome = xCAT::Utils->getHomeDir("root");
|
|
my $zonehash = xCAT::Zone->getzoneinfo($::CALLBACK, \@nodes);
|
|
|
|
foreach my $zonename (keys %$zonehash) {
|
|
|
|
# build list of nodes
|
|
my $zonenodelist = "";
|
|
foreach my $node (@{ $zonehash->{$zonename}->{nodes} }) {
|
|
$zonenodelist .= $node;
|
|
$zonenodelist .= ",";
|
|
|
|
}
|
|
$zonenodelist =~ s/,$//; # remove last comma
|
|
# if any nodes defined for the zone
|
|
if ($zonenodelist) {
|
|
|
|
# check to see if we enable passwordless ssh between the nodes
|
|
if (!(defined($zonehash->{$zonename}->{sshbetweennodes})) ||
|
|
(($zonehash->{$zonename}->{sshbetweennodes} =~ /^yes$/i)
|
|
|| ($zonehash->{$zonename}->{sshbetweennodes} eq "1"))) {
|
|
|
|
$ENV{'DSH_ENABLE_SSH'} = "YES";
|
|
} else {
|
|
delete $ENV{'DSH_ENABLE_SSH'}; # do not enable passwordless ssh
|
|
}
|
|
|
|
# point to the ssh keys to send for this zone
|
|
my $keydir = $zonehash->{$zonename}->{sshkeydir};
|
|
|
|
# check to see if the id_rsa and id_rsa.pub key is in the directory
|
|
my $key = "$keydir/id_rsa";
|
|
my $key2 = "$keydir/id_rsa.pub";
|
|
|
|
# Check to see if empty
|
|
if (!(-e $key)) {
|
|
my $rsp = {};
|
|
$rsp->{error}->[0] =
|
|
"The $key file does not exist for $zonename. Need to use chzone to regenerate the keys.";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK, 1);
|
|
return 1;
|
|
}
|
|
if (!(-e $key2)) {
|
|
my $rsp = {};
|
|
$rsp->{error}->[0] =
|
|
"The $key2 file does not exist for $zonename. Need to use chzone to regenerate the keys.";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK, 1);
|
|
return 1;
|
|
|
|
}
|
|
|
|
# now put copy.sh in the zone directory from ~/.ssh
|
|
my $rootkeydir = "$roothome/.ssh";
|
|
if ($rootkeydir ne $keydir) { # the zone keydir is not the same as ~/.ssh.
|
|
$cmd = "cp $rootkeydir/copy.sh $keydir";
|
|
xCAT::Utils->runcmd($cmd, 0);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp = {};
|
|
$rsp->{error}->[0] =
|
|
"Could not copy copy.sh to the zone key dir";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
# Also create $keydir/tmp and put root's id_rsa.pub (in authorized_keys) for the transfer
|
|
$cmd = "mkdir -p $keydir/tmp";
|
|
xCAT::Utils->runcmd($cmd, 0);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp = {};
|
|
$rsp->{error}->[0] =
|
|
"Could not mkdir the zone $keydir/tmp";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
|
|
return 1;
|
|
}
|
|
|
|
# create authorized_keys file
|
|
if (xCAT::Utils->isMN()) { # if on Management Node
|
|
$cmd = " cp $roothome/.ssh/id_rsa.pub $keydir/tmp/authorized_keys";
|
|
} else { # SN
|
|
$cmd = " cp $roothome/.ssh/authorized_keys $keydir/tmp/authorized_keys";
|
|
}
|
|
xCAT::Utils->runcmd($cmd, 0);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
$rsp->{data}->[0] = "$cmd failed.\n";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
|
|
return (1);
|
|
}
|
|
else
|
|
{
|
|
chmod 0600, "$keydir/.ssh/tmp/authorized_keys";
|
|
}
|
|
|
|
# strip off .ssh
|
|
my ($newkeydir, $ssh) = (split(/\.ssh/, $keydir));
|
|
$ENV{'DSH_ZONE_SSHKEYS'} = $newkeydir;
|
|
|
|
# send the keys to the nodes
|
|
my $rc = xCAT::RemoteShellExp->remoteshellexp("s", $::CALLBACK, "/usr/bin/ssh",
|
|
$zonenodelist, $expecttimeout);
|
|
if ($rc != 0)
|
|
{
|
|
$rsp = {};
|
|
$rsp->{data}->[0] = "remoteshellexp failed sending keys to $zonename.";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
|
|
|
|
}
|
|
} # end nodes in the zone
|
|
|
|
} # end for each zone
|
|
|
|
return (0);
|
|
}
|
|
|
|
#--------------------------------------------------------------------------------
|
|
|
|
=head3 cpSSHFiles
|
|
|
|
Builds authorized_keyfiles for root
|
|
|
|
Arguments:
|
|
install directory path
|
|
Returns:
|
|
|
|
Globals:
|
|
$::CALLBACK
|
|
Error:
|
|
|
|
Example:
|
|
xCAT::TableUtils->cpSSHFiles($dir);
|
|
|
|
Comments:
|
|
none
|
|
|
|
=cut
|
|
|
|
#--------------------------------------------------------------------------------
|
|
|
|
|
|
sub cpSSHFiles
|
|
{
|
|
my ($class, $SSHdir) = @_;
|
|
my ($cmd, $rc);
|
|
my $rsp = {};
|
|
if ($::VERBOSE)
|
|
{
|
|
$rsp->{data}->[0] = "Copying SSH Keys";
|
|
xCAT::MsgUtils->message("I", $rsp, $::CALLBACK);
|
|
}
|
|
my $home = xCAT::Utils->getHomeDir("root");
|
|
|
|
|
|
if (xCAT::Utils->isMN()) { # if on Management Node
|
|
if (!(-e "$home/.ssh/id_rsa.pub")) # only using rsa
|
|
{
|
|
$rsp->{data}->[0] = "Public key id_rsa.pub was missing in the .ssh directory.";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
|
|
return 1;
|
|
}
|
|
|
|
# copy to id_rsa public key to authorized_keys in the install directory
|
|
my $authorized_keys = "$SSHdir/authorized_keys";
|
|
|
|
# changed from identity.pub
|
|
$cmd = " cp $home/.ssh/id_rsa.pub $authorized_keys";
|
|
xCAT::Utils->runcmd($cmd, 0);
|
|
$rsp = {};
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
$rsp->{data}->[0] = "$cmd failed.\n";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
|
|
return (1);
|
|
|
|
}
|
|
else
|
|
{
|
|
if ($::VERBOSE)
|
|
{
|
|
$rsp->{data}->[0] = "$cmd succeeded.\n";
|
|
xCAT::MsgUtils->message("I", $rsp, $::CALLBACK);
|
|
}
|
|
}
|
|
} # end is MN
|
|
|
|
# on MN and SN
|
|
# make tmp directory to hold authorized_keys for node transfer
|
|
if (!(-e "$home/.ssh/tmp")) {
|
|
$cmd = " mkdir $home/.ssh/tmp";
|
|
xCAT::Utils->runcmd($cmd, 0);
|
|
$rsp = {};
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
$rsp->{data}->[0] = "$cmd failed.\n";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
|
|
return (1);
|
|
|
|
}
|
|
}
|
|
|
|
# create authorized_keys file
|
|
if (xCAT::Utils->isMN()) { # if on Management Node
|
|
$cmd = " cp $home/.ssh/id_rsa.pub $home/.ssh/tmp/authorized_keys";
|
|
} else { # SN
|
|
$cmd = " cp $home/.ssh/authorized_keys $home/.ssh/tmp/authorized_keys";
|
|
}
|
|
xCAT::Utils->runcmd($cmd, 0);
|
|
$rsp = {};
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
$rsp->{data}->[0] = "$cmd failed.\n";
|
|
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
|
|
return (1);
|
|
|
|
}
|
|
else
|
|
{
|
|
chmod 0600, "$home/.ssh/tmp/authorized_keys";
|
|
if ($::VERBOSE)
|
|
{
|
|
$rsp->{data}->[0] = "$cmd succeeded.\n";
|
|
xCAT::MsgUtils->message("I", $rsp, $::CALLBACK);
|
|
}
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 GetNodeOSARCH
|
|
Reads the database for the OS and Arch of the input Node
|
|
Arguments:
|
|
Node
|
|
Returns:
|
|
$et->{'os'}
|
|
$et->{'arch'}
|
|
Globals:
|
|
none
|
|
Error:
|
|
none
|
|
Example:
|
|
$master=(xCAT::TableUtils->GetNodeOSARCH($node))
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub GetNodeOSARCH
|
|
{
|
|
my ($class, $node) = @_;
|
|
my $typetab = xCAT::Table->new('nodetype');
|
|
unless ($typetab)
|
|
{
|
|
xCAT::MsgUtils->message('S',
|
|
"Unable to open nodetype table.\n");
|
|
return 1;
|
|
}
|
|
my $et = $typetab->getNodeAttribs($node, [ 'os', 'arch' ]);
|
|
unless ($et and $et->{'os'} and $et->{'arch'})
|
|
{
|
|
xCAT::MsgUtils->message('S',
|
|
"No os/arch setting in nodetype table for $node.\n");
|
|
return 1;
|
|
}
|
|
|
|
return $et;
|
|
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 logEventsToDatabase
|
|
Logs the given events info to the xCAT's 'eventlog' database
|
|
Arguments:
|
|
arrayref -- A pointer to an array. Each element is a hash that contains an events.
|
|
The hash should contain the at least one of the following keys:
|
|
eventtime -- The format is "yyyy-mm-dd hh:mm:ss".
|
|
If omitted, the current date and time will be used.
|
|
monitor -- The name of the monitor that monitors this event.
|
|
monnode -- The node that monitors this event.
|
|
node -- The node where the event occurred.
|
|
application -- The application that reports the event.
|
|
component -- The component where the event occurred.
|
|
id -- The location or the resource name where the event occurred.
|
|
severity -- The severity of the event. Valid values are: informational, warning, critical.
|
|
message -- The full description of the event.
|
|
rawdata -- The data that associated with the event.
|
|
Returns:
|
|
(ret code, error message)
|
|
Example:
|
|
my @a=();
|
|
my $event={
|
|
eventtime=>"2009-07-28 23:02:03",
|
|
node => 'node1',
|
|
rawdata => 'kjdlkfajlfjdlksaj',
|
|
};
|
|
push (@a, $event);
|
|
|
|
my $event1={
|
|
node => 'cu03cp',
|
|
monnode => 'cu03sv',
|
|
application => 'RMC',
|
|
component => 'IBM.Sensor',
|
|
id => 'AIXErrorLogSensor',
|
|
severity => 'warning',
|
|
};
|
|
push(@a, $event1);
|
|
xCAT::TableUtils->logEventsToDatabase(\@a);
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub logEventsToDatabase
|
|
{
|
|
my $pEvents = shift;
|
|
if (($pEvents) && ($pEvents =~ /xCAT::TableUtils/))
|
|
{
|
|
$pEvents = shift;
|
|
}
|
|
|
|
if (($pEvents) && (@$pEvents > 0))
|
|
{
|
|
my $currtime;
|
|
my $tab = xCAT::Table->new("eventlog", -create => 1, -autocommit => 0);
|
|
if (!$tab)
|
|
{
|
|
return (1, "The evnetlog table cannot be opened.");
|
|
}
|
|
|
|
foreach my $event (@$pEvents)
|
|
{
|
|
|
|
#create event time if it does not exist
|
|
if (!exists($event->{eventtime}))
|
|
{
|
|
if (!$currtime)
|
|
{
|
|
my (
|
|
$sec, $min, $hour, $mday, $mon,
|
|
$year, $wday, $yday, $isdst
|
|
)
|
|
= localtime(time);
|
|
$currtime = sprintf("%04d-%02d-%02d %02d:%02d:%02d",
|
|
$year + 1900, $mon + 1, $mday,
|
|
$hour, $min, $sec);
|
|
}
|
|
$event->{eventtime} = $currtime;
|
|
}
|
|
my @ret = $tab->setAttribs(undef, $event);
|
|
if (@ret > 1) { return (1, $ret[1]); }
|
|
}
|
|
$tab->commit;
|
|
}
|
|
|
|
return (0, "");
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 logEventsToTealDatabase
|
|
Logs the given events info to the TEAL's 'x_tealeventlog' database
|
|
Arguments:
|
|
arrayref -- A pointer to an array. Each element is a hash that contains an events.
|
|
Returns:
|
|
(ret code, error message)
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub logEventsToTealDatabase
|
|
{
|
|
my $pEvents = shift;
|
|
if (($pEvents) && ($pEvents =~ /xCAT::TableUtils/))
|
|
{
|
|
$pEvents = shift;
|
|
}
|
|
|
|
if (($pEvents) && (@$pEvents > 0))
|
|
{
|
|
my $currtime;
|
|
my $tab = xCAT::Table->new("x_tealeventlog", -create => 1, -autocommit => 0);
|
|
if (!$tab)
|
|
{
|
|
return (1, "The x_tealeventlog table cannot be opened.");
|
|
}
|
|
|
|
foreach my $event (@$pEvents)
|
|
{
|
|
my @ret = $tab->setAttribs(undef, $event);
|
|
if (@ret > 1) { return (1, $ret[1]); }
|
|
}
|
|
$tab->commit;
|
|
}
|
|
|
|
return (0, "");
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 setAppStatus
|
|
Description:
|
|
Set an AppStatus value for a specific application in the nodelist
|
|
appstatus attribute for a list of nodes
|
|
Arguments:
|
|
@nodes
|
|
$application
|
|
$status
|
|
Returns:
|
|
Return result of call to setNodesAttribs
|
|
Globals:
|
|
none
|
|
Error:
|
|
none
|
|
Example:
|
|
xCAT::TableUtils->setAppStatus(\@nodes,$application,$status);
|
|
Comments:
|
|
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
sub setAppStatus
|
|
{
|
|
|
|
my ($class, $nodes_ref, $application, $status) = @_;
|
|
my @nodes = @$nodes_ref;
|
|
|
|
#get current local time to set in appstatustime attribute
|
|
my (
|
|
$sec, $min, $hour, $mday, $mon,
|
|
$year, $wday, $yday, $isdst
|
|
)
|
|
= localtime(time);
|
|
my $currtime = sprintf("%02d-%02d-%04d %02d:%02d:%02d",
|
|
$mon + 1, $mday, $year + 1900,
|
|
$hour, $min, $sec);
|
|
|
|
my $nltab = xCAT::Table->new('nodelist');
|
|
my $nodeappstat = $nltab->getNodesAttribs(\@nodes, ['appstatus']);
|
|
|
|
my %new_nodeappstat;
|
|
foreach my $node (keys %$nodeappstat) {
|
|
if ($node =~ /^\s*$/) { next; } # Skip blank node names
|
|
my $new_appstat = "";
|
|
my $changed = 0;
|
|
|
|
# Search current appstatus and change if app entry exists
|
|
my $cur_appstat = $nodeappstat->{$node}->[0]->{appstatus};
|
|
if ($cur_appstat) {
|
|
my @appstatus_entries = split(/,/, $cur_appstat);
|
|
foreach my $appstat (@appstatus_entries) {
|
|
my ($app, $stat) = split(/=/, $appstat);
|
|
if ($app eq $application) {
|
|
$new_appstat .= ",$app=$status";
|
|
$changed = 1;
|
|
} else {
|
|
$new_appstat .= ",$appstat";
|
|
}
|
|
}
|
|
}
|
|
|
|
# If no app entry exists, add it
|
|
if (!$changed) {
|
|
$new_appstat .= ",$application=$status";
|
|
}
|
|
$new_appstat =~ s/^,//;
|
|
$new_nodeappstat{$node}->{appstatus} = $new_appstat;
|
|
$new_nodeappstat{$node}->{appstatustime} = $currtime;
|
|
}
|
|
|
|
return $nltab->setNodesAttribs(\%new_nodeappstat);
|
|
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 setUpdateStatus
|
|
Description:
|
|
Set the updatestatus attribute for a list of nodes during "updatenode"
|
|
Arguments:
|
|
@nodes
|
|
$status
|
|
Returns:
|
|
none
|
|
|
|
Globals:
|
|
none
|
|
Error:
|
|
none
|
|
Example:
|
|
xCAT::TableUtils->setUpdateStatus(\@nodes,$status);
|
|
Comments:
|
|
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
sub setUpdateStatus
|
|
{
|
|
|
|
|
|
my ($class, $nodes_ref, $status) = @_;
|
|
my @nodes = @$nodes_ref;
|
|
|
|
|
|
|
|
#get current local time to set in Updatestatustime attribute
|
|
my (
|
|
$sec, $min, $hour, $mday, $mon,
|
|
$year, $wday, $yday, $isdst
|
|
)
|
|
= localtime(time);
|
|
my $currtime = sprintf("%02d-%02d-%04d %02d:%02d:%02d",
|
|
$mon + 1, $mday, $year + 1900,
|
|
$hour, $min, $sec);
|
|
|
|
my $nltab = xCAT::Table->new('nodelist');
|
|
if ($nltab) {
|
|
if (@nodes > 0) {
|
|
my %updates;
|
|
|
|
foreach my $node (@nodes)
|
|
{
|
|
$updates{$node}{'updatestatus'} = $status;
|
|
$updates{$node}{'updatestatustime'} = $currtime;
|
|
}
|
|
|
|
$nltab->setNodesAttribs(\%updates);
|
|
}
|
|
$nltab->close;
|
|
}
|
|
return;
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 getAppStatus
|
|
Description:
|
|
Get an AppStatus value for a specific application from the
|
|
nodelist appstatus attribute for a list of nodes
|
|
Arguments:
|
|
@nodes
|
|
$application
|
|
Returns:
|
|
a hashref of nodes set to application status value
|
|
Globals:
|
|
none
|
|
Error:
|
|
none
|
|
Example:
|
|
my $appstatus = $xCAT::TableUtils->getAppStatus(\@nodes,$application);
|
|
my $node1_status = $appstatus->{node1};
|
|
Comments:
|
|
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
sub getAppStatus
|
|
{
|
|
|
|
my ($class, $nodes_ref, $application) = @_;
|
|
my @nodes = @$nodes_ref;
|
|
|
|
# FIXME: why autocommit matters for a read-only subroutine getNodesAttribs?
|
|
# but could not get the appstatus without the autocommit=0
|
|
my $nltab = xCAT::Table->new('nodelist', -autocommit => 0);
|
|
my $nodeappstat = $nltab->getNodesAttribs(\@nodes, ['appstatus']);
|
|
|
|
my $ret_nodeappstat;
|
|
foreach my $node (keys %$nodeappstat) {
|
|
my $cur_appstat = $nodeappstat->{$node}->[0]->{appstatus};
|
|
my $found = 0;
|
|
if ($cur_appstat) {
|
|
my @appstatus_entries = split(/,/, $cur_appstat);
|
|
foreach my $appstat (@appstatus_entries) {
|
|
my ($app, $stat) = split(/=/, $appstat);
|
|
if ($app eq $application) {
|
|
$ret_nodeappstat->{$node} = $stat;
|
|
$found = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
# If no app entry exists, return empty
|
|
if (!$found) {
|
|
$ret_nodeappstat->{$node} = "";
|
|
}
|
|
}
|
|
|
|
return $ret_nodeappstat;
|
|
|
|
}
|
|
|
|
#-----------------------------------------------------------------------
|
|
|
|
=head3
|
|
get_site_attribute
|
|
|
|
Arguments:
|
|
$attribute -- the attribute you want to get
|
|
$dvalue -- Optional, the default string value if the attribute does not exist
|
|
Returns:
|
|
The value of the attribute requested from the site table
|
|
Globals:
|
|
%::XCATSITEVALS
|
|
Error:
|
|
undef
|
|
Example:
|
|
@attr=xCAT::TableUtils->get_site_attribute($attribute);
|
|
Comments:
|
|
none
|
|
|
|
=cut
|
|
|
|
#------------------------------------------------------------------------
|
|
sub get_site_attribute
|
|
{
|
|
my ($class, $attr, $dvalue) = @_;
|
|
|
|
my $values;
|
|
if (%::XCATSITEVALS) {
|
|
$values = ($::XCATSITEVALS{$attr});
|
|
} else {
|
|
my $sitetab = xCAT::Table->new('site');
|
|
if ($sitetab)
|
|
{
|
|
(my $ref) = $sitetab->getAttribs({ key => $attr }, 'value');
|
|
if ($ref)
|
|
{
|
|
$values = $ref->{value};
|
|
}
|
|
$sitetab->close;
|
|
}
|
|
else
|
|
{
|
|
xCAT::MsgUtils->message("E", " Could not read the site table\n");
|
|
|
|
}
|
|
}
|
|
return $values if ( defined $values);
|
|
return $dvalue;
|
|
}
|
|
|
|
|
|
#--------------------------------------------------------------------------------
|
|
|
|
=head3 getInstallDir
|
|
|
|
Get location of the directory, used to hold the node deployment packages.
|
|
|
|
Arguments:
|
|
none
|
|
Returns:
|
|
path to install directory defined at site.installdir.
|
|
Globals:
|
|
none
|
|
Error:
|
|
none
|
|
Example:
|
|
$installdir = xCAT::TableUtils->getInstallDir();
|
|
Comments:
|
|
none
|
|
|
|
=cut
|
|
|
|
#--------------------------------------------------------------------------------
|
|
|
|
sub getInstallDir
|
|
{
|
|
# Default installdir location. Used by default in most Linux distros.
|
|
my $installdir = "/install";
|
|
|
|
# Try to lookup real installdir place.
|
|
my @installdir1 = xCAT::TableUtils->get_site_attribute("installdir");
|
|
|
|
# Use fetched value, incase successful database lookup.
|
|
if ($installdir1[0])
|
|
{
|
|
$installdir = $installdir1[0];
|
|
}
|
|
|
|
return $installdir;
|
|
}
|
|
|
|
|
|
#--------------------------------------------------------------------------------
|
|
|
|
=head3 getTftpDir
|
|
|
|
Get location of the directory, used to hold network boot files.
|
|
|
|
Arguments:
|
|
none
|
|
Returns:
|
|
path to TFTP directory defined at site.tftpdir.
|
|
Globals:
|
|
none
|
|
Error:
|
|
none
|
|
Example:
|
|
$tftpdir = xCAT::TableUtils->getTftpDir();
|
|
Comments:
|
|
none
|
|
|
|
=cut
|
|
|
|
#--------------------------------------------------------------------------------
|
|
|
|
sub getTftpDir
|
|
{
|
|
# Default tftpdir location. Used by default in most Linux distros.
|
|
my $tftpdir = "/tftpboot";
|
|
|
|
# Try to lookup real tftpdir place.
|
|
my @tftpdir1 = xCAT::TableUtils->get_site_attribute("tftpdir");
|
|
|
|
# Use fetched value, incase successful database lookup.
|
|
if ($tftpdir1[0])
|
|
{
|
|
$tftpdir = $tftpdir1[0];
|
|
}
|
|
|
|
return $tftpdir;
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 GetMasterNodeName
|
|
Reads the database for the Master node name for the input node
|
|
Arguments:
|
|
Node
|
|
Returns:
|
|
MasterHostName
|
|
Globals:
|
|
none
|
|
Error:
|
|
none
|
|
Example:
|
|
$master=(xCAT::TableUtils->GetMasterNodeName($node))
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub GetMasterNodeName
|
|
{
|
|
my ($class, $node) = @_;
|
|
my $master;
|
|
my $noderestab = xCAT::Table->new('noderes');
|
|
unless ($noderestab)
|
|
{
|
|
xCAT::MsgUtils->message('S',
|
|
"Unable to open noderes table.\n");
|
|
return 1;
|
|
}
|
|
my @masters = xCAT::TableUtils->get_site_attribute("master");
|
|
$master = $masters[0];
|
|
|
|
my $et = $noderestab->getNodeAttribs($node, ['xcatmaster']);
|
|
if ($et and $et->{'xcatmaster'})
|
|
{
|
|
$master = $et->{'xcatmaster'};
|
|
}
|
|
unless ($master)
|
|
{
|
|
xCAT::MsgUtils->message('S', "Unable to identify master for $node.\n");
|
|
$noderestab->close;
|
|
return 1;
|
|
}
|
|
|
|
$noderestab->close;
|
|
return $master;
|
|
}
|
|
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
=head3 create_postscripts_tar
|
|
|
|
This routine will tar and compress the /install/postscripts directory
|
|
and place in /install/autoinst/xcat_postscripts.Z
|
|
|
|
input: none
|
|
output:
|
|
example: $rc=xCAT::TableUtils->create_postscripts_tar();
|
|
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
sub create_postscripts_tar
|
|
{
|
|
my ($class) = @_;
|
|
my $installdir = xCAT::TableUtils->getInstallDir();
|
|
my $cmd;
|
|
if (!(-e "$installdir/autoinst"))
|
|
{
|
|
mkdir("$installdir/autoinst");
|
|
}
|
|
|
|
$cmd =
|
|
"cd $installdir/postscripts; tar -cf $installdir/autoinst/xcatpost.tar * .ssh/* _xcat/*; gzip -f $installdir/autoinst/xcatpost.tar";
|
|
my @result = xCAT::Utils->runcmd($cmd, 0);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
xCAT::MsgUtils->message("S", "Error from $cmd\n");
|
|
return $::RUNCMD_RC;
|
|
}
|
|
|
|
# for AIX add an entry to the /etc/tftpaccess.ctrl file so
|
|
# we can tftp the tar file from the node
|
|
if (xCAT::Utils->isAIX())
|
|
{
|
|
my $tftpctlfile = "/etc/tftpaccess.ctl";
|
|
my $entry = "allow:$installdir/autoinst/xcatpost.tar.gz";
|
|
|
|
# see if there is already an entry
|
|
my $cmd = "cat $tftpctlfile | grep xcatpost";
|
|
my @result = xCAT::Utils->runcmd("$cmd", -1);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
|
|
# not found so add it
|
|
unless (open(TFTPFILE, ">>$tftpctlfile"))
|
|
{
|
|
xCAT::MsgUtils->message("S", "Could not open $tftpctlfile.\n");
|
|
return $::RUNCMD_RC;
|
|
}
|
|
|
|
print TFTPFILE $entry;
|
|
|
|
close(TFTPFILE);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
=head3 get_site_Master
|
|
|
|
Reads the site table for the Master attribute and returns it.
|
|
input: none
|
|
output : value of site.Master attribute , blank is an error
|
|
example: $Master =xCAT::TableUtils->get_site_Master();
|
|
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
sub get_site_Master
|
|
{
|
|
if ($::XCATSITEVALS{master}) {
|
|
return $::XCATSITEVALS{master};
|
|
}
|
|
my $Master;
|
|
my $sitetab = xCAT::Table->new('site');
|
|
(my $et) = $sitetab->getAttribs({ key => "master" }, 'value');
|
|
if ($et and $et->{value})
|
|
{
|
|
$Master = $et->{value};
|
|
}
|
|
else
|
|
{
|
|
# this msg can be missleading
|
|
# xCAT::MsgUtils->message('E',
|
|
# "Unable to read site table for Master attribute.\n");
|
|
}
|
|
return $Master;
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 checkCredFiles
|
|
Checks the various credential files on the Management Node to
|
|
make sure the permission are correct for using and transferring
|
|
to the nodes and service nodes.
|
|
Also removes /install/postscripts/etc/xcat/cfgloc if found
|
|
Arguments:
|
|
$callback
|
|
Returns:
|
|
0 - ok
|
|
Globals:
|
|
none
|
|
Error:
|
|
warnings of possible missing files and directories
|
|
Example:
|
|
my $rc=xCAT::TableUtils->checkCreds
|
|
Comments:
|
|
none
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub checkCredFiles
|
|
{
|
|
my $lib = shift;
|
|
my $cb = shift;
|
|
my $installdir = xCAT::TableUtils->getInstallDir();
|
|
my $dir = "$installdir/postscripts/_xcat";
|
|
if (-d $dir)
|
|
{
|
|
my $file = "$dir/ca.pem";
|
|
if (-e $file)
|
|
{
|
|
|
|
my $cmd = "/bin/chmod 0644 $file";
|
|
my $outref = xCAT::Utils->runcmd("$cmd", 0);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp = {};
|
|
$rsp->{data}->[0] = "Error on command: $cmd";
|
|
xCAT::MsgUtils->message("I", $rsp, $cb);
|
|
|
|
}
|
|
}
|
|
else
|
|
{ # ca.pem missing
|
|
my $rsp = {};
|
|
$rsp->{data}->[0] = "Error: $file is missing. Run xcatconfig (no force)";
|
|
xCAT::MsgUtils->message("I", $rsp, $cb);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
my $rsp = {};
|
|
$rsp->{data}->[0] = "Error: $dir is missing.";
|
|
xCAT::MsgUtils->message("I", $rsp, $cb);
|
|
}
|
|
|
|
|
|
$dir = "$installdir/postscripts/ca";
|
|
if (-d $dir)
|
|
{
|
|
my $file = "$dir/ca-cert.pem";
|
|
if (-e $file)
|
|
{
|
|
|
|
my $cmd = "/bin/chmod 0644 $file";
|
|
my $outref = xCAT::Utils->runcmd("$cmd", 0);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp = {};
|
|
$rsp->{data}->[0] = "Error on command: $cmd";
|
|
xCAT::MsgUtils->message("I", $rsp, $cb);
|
|
|
|
}
|
|
}
|
|
else
|
|
{ # ca_cert.pem missing
|
|
my $rsp = {};
|
|
$rsp->{data}->[0] = "Error: $file is missing. Run xcatconfig (no force)";
|
|
xCAT::MsgUtils->message("I", $rsp, $cb);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
my $rsp = {};
|
|
$rsp->{data}->[0] = "Error: $dir is missing.";
|
|
xCAT::MsgUtils->message("I", $rsp, $cb);
|
|
}
|
|
|
|
|
|
# ssh hostkeys
|
|
$dir = "$installdir/postscripts/hostkeys";
|
|
if (-d $dir)
|
|
{
|
|
my $file = "$dir/ssh_host_rsa_key.pub";
|
|
if (-e $file)
|
|
{
|
|
my $file2 = "$dir/*.pub"; # all public keys
|
|
my $cmd = "/bin/chmod 0644 $file2";
|
|
my $outref = xCAT::Utils->runcmd("$cmd", 0);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp = {};
|
|
$rsp->{data}->[0] = "Error on command: $cmd";
|
|
xCAT::MsgUtils->message("I", $rsp, $cb);
|
|
|
|
}
|
|
}
|
|
else
|
|
{ # hostkey missing
|
|
my $rsp = {};
|
|
$rsp->{data}->[0] = "Error: $file is missing. Run xcatconfig (no force)";
|
|
xCAT::MsgUtils->message("I", $rsp, $cb);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
my $rsp = {};
|
|
$rsp->{data}->[0] = "Error: $dir is missing.";
|
|
xCAT::MsgUtils->message("I", $rsp, $cb);
|
|
}
|
|
|
|
# ssh hostkeys
|
|
$dir = "/etc/xcat/hostkeys";
|
|
if (-d $dir)
|
|
{
|
|
my $file = "$dir/ssh_host_rsa_key.pub";
|
|
if (-e $file)
|
|
{
|
|
my $file2 = "$dir/*.pub"; # all public keys
|
|
my $cmd = "/bin/chmod 0644 $file2";
|
|
my $outref = xCAT::Utils->runcmd("$cmd", 0);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp = {};
|
|
$rsp->{data}->[0] = "Error on command: $cmd";
|
|
xCAT::MsgUtils->message("I", $rsp, $cb);
|
|
|
|
}
|
|
}
|
|
else
|
|
{ # hostkey missing
|
|
my $rsp = {};
|
|
$rsp->{data}->[0] = "Error: $file is missing. Run xcatconfig (no force)";
|
|
xCAT::MsgUtils->message("I", $rsp, $cb);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
my $rsp = {};
|
|
$rsp->{data}->[0] = "Error: $dir is missing.";
|
|
xCAT::MsgUtils->message("I", $rsp, $cb);
|
|
}
|
|
|
|
# ssh directory
|
|
$dir = "$installdir/postscripts/_ssh";
|
|
|
|
if (-d $dir)
|
|
{
|
|
my $file = "$dir/authorized_keys";
|
|
if (-e $file)
|
|
{
|
|
my $file2 = "$dir/authorized_keys*";
|
|
my $cmd = "/bin/chmod 0644 $file2";
|
|
my $outref = xCAT::Utils->runcmd("$cmd", 0);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp = {};
|
|
$rsp->{data}->[0] = "Error on command: $cmd";
|
|
xCAT::MsgUtils->message("I", $rsp, $cb);
|
|
|
|
}
|
|
|
|
# make install script executable
|
|
$file2 = "$dir/copy.sh";
|
|
if (-e $file2)
|
|
{
|
|
my $cmd = "/bin/chmod 0744 $file2";
|
|
my $outref = xCAT::Utils->runcmd("$cmd", 0);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp = {};
|
|
$rsp->{data}->[0] = "Error on command: $cmd";
|
|
xCAT::MsgUtils->message("I", $rsp, $cb);
|
|
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{ # authorized keys missing
|
|
my $rsp = {};
|
|
$rsp->{data}->[0] = "Error: $file is missing. Run xcatconfig (no force)";
|
|
xCAT::MsgUtils->message("I", $rsp, $cb);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
my $rsp = {};
|
|
$rsp->{data}->[0] = "Error: $dir is missing.";
|
|
xCAT::MsgUtils->message("I", $rsp, $cb);
|
|
}
|
|
|
|
# remove any old cfgloc files
|
|
my $file = "$installdir/postscripts/etc/xcat/cfgloc";
|
|
if (-e $file)
|
|
{
|
|
|
|
my $cmd = "/bin/rm $file";
|
|
my $outref = xCAT::Utils->runcmd("$cmd", 0);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp = {};
|
|
$rsp->{data}->[0] = "Error on command: $cmd";
|
|
xCAT::MsgUtils->message("I", $rsp, $cb);
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 enableSSH
|
|
Description:
|
|
Reads the site.sshbetweennodes attribute and determines
|
|
if the input node should be enabled to ssh between nodes
|
|
Arguments:
|
|
$node
|
|
Returns:
|
|
1 = enable ssh
|
|
0 = do not enable ssh
|
|
Globals:
|
|
none
|
|
Error:
|
|
none
|
|
Example:
|
|
my $eable = xCAT::TableUtils->enablessh($node);
|
|
Comments:
|
|
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
sub enablessh
|
|
{
|
|
|
|
my ($class, $node) = @_;
|
|
my $enablessh = 1;
|
|
|
|
if (xCAT::Utils->isSN($node)) {
|
|
$enablessh = 1; # service nodes always enabled
|
|
|
|
} else {
|
|
|
|
# if not a service node we need to check, before enabling
|
|
my $values;
|
|
my @vals = xCAT::TableUtils->get_site_attribute("sshbetweennodes");
|
|
$values = $vals[0];
|
|
if ($values) {
|
|
my @groups = split(/,/, $values);
|
|
if (grep(/^ALLGROUPS$/, @groups))
|
|
{
|
|
$enablessh = 1;
|
|
}
|
|
else
|
|
{
|
|
if (grep(/^NOGROUPS$/, @groups))
|
|
{
|
|
$enablessh = 0;
|
|
}
|
|
else
|
|
{ # check to see if the node is a member of a group
|
|
my $ismember = 0;
|
|
foreach my $group (@groups)
|
|
{
|
|
$ismember = xCAT::Utils->isMemberofGroup($node, $group);
|
|
if ($ismember == 1)
|
|
{
|
|
last;
|
|
}
|
|
}
|
|
if ($ismember == 1)
|
|
{
|
|
$enablessh = 1;
|
|
}
|
|
else
|
|
{
|
|
$enablessh = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{ # does not exist, set default
|
|
$enablessh = 1;
|
|
|
|
}
|
|
}
|
|
return $enablessh;
|
|
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 enableSSH
|
|
Description:
|
|
The function is same as enablessh() above. Before using this function,
|
|
the $sn_hash for noderange, and $groups_hash for site.sshbetweennodes should be
|
|
got. This is performance improvement.
|
|
Arguments:
|
|
$node -- node name
|
|
$sn_hash -- if the node is one sn, key is the node name, and value is 1.
|
|
if the node is not a sn, the key isn't in this hash
|
|
$groups_hash -- there are two keys:
|
|
1. Each group in the value of site.sshbetweennodes could be the key
|
|
2. Each node in the groups from the value of site.sshbetweennodes , if the
|
|
value isn't ALLGROUPS or NOGROUPS.
|
|
|
|
Returns:
|
|
1 = enable ssh
|
|
0 = do not enable ssh
|
|
Globals:
|
|
none
|
|
Error:
|
|
none
|
|
Example:
|
|
my $enable = xCAT::TableUtils->enableSSH($node);
|
|
Comments:
|
|
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
sub enableSSH
|
|
{
|
|
|
|
my ($class, $node, $sn_hash, $groups_hash) = @_;
|
|
my $enablessh = 1;
|
|
|
|
if (defined($sn_hash) && defined($sn_hash->{node}) && $sn_hash->{$node} == 1) {
|
|
$enablessh = 1; # service nodes always enabled
|
|
|
|
} else {
|
|
|
|
# if not a service node we need to check, before enabling
|
|
if (keys %$groups_hash) { # not empty
|
|
if ($groups_hash->{ALLGROUPS} == 1)
|
|
{
|
|
$enablessh = 1;
|
|
}
|
|
else
|
|
{
|
|
if ($groups_hash->{NOGROUPS} == 1)
|
|
{
|
|
$enablessh = 0;
|
|
}
|
|
else
|
|
{ # check to see if the node is a member of a group
|
|
my $ismember = 0;
|
|
$ismember = $groups_hash->{$node};
|
|
|
|
if ($ismember == 1)
|
|
{
|
|
$enablessh = 1;
|
|
}
|
|
else
|
|
{
|
|
$enablessh = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{ # does not exist, set default
|
|
$enablessh = 1;
|
|
|
|
}
|
|
}
|
|
return $enablessh;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
|
|
=head3 getrootimage
|
|
Get the directory of root image for a node;
|
|
Note: This subroutine only works for diskless node
|
|
|
|
Arguments:
|
|
$node
|
|
Returns:
|
|
string - directory of the root image
|
|
undef - this is not a diskless node or the root image does not existed
|
|
Globals:
|
|
none
|
|
Error:
|
|
Example:
|
|
my $node_syncfile=xCAT::TableUtils->getrootimage($node);
|
|
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
sub getrootimage()
|
|
{
|
|
my $node = shift;
|
|
my $installdir = xCAT::TableUtils->getInstallDir();
|
|
if (($node) && ($node =~ /xCAT::TableUtils/))
|
|
{
|
|
$node = shift;
|
|
}
|
|
|
|
# get the os,arch,profile attributes for the nodes
|
|
my $nodetype_t = xCAT::Table->new('nodetype');
|
|
unless ($nodetype_t) {
|
|
return;
|
|
}
|
|
my $nodetype_v = $nodetype_t->getNodeAttribs($node, [ 'profile', 'os', 'arch' ]);
|
|
my $profile = $nodetype_v->{'profile'};
|
|
my $os = $nodetype_v->{'os'};
|
|
my $arch = $nodetype_v->{'arch'};
|
|
|
|
if ($^O eq "linux") {
|
|
my $rootdir = "$installdir/netboot/$os/$arch/$profile/rootimg/";
|
|
if (-d $rootdir) {
|
|
return $rootdir;
|
|
} else {
|
|
return undef;
|
|
}
|
|
} else {
|
|
|
|
# For AIX
|
|
}
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
|
|
=head3 getimagenames
|
|
Get an array of osimagenames that correspond to the input node array;
|
|
|
|
Arguments:
|
|
Array of nodes
|
|
Returns:
|
|
array of all the osimage names that are the provmethod for the nodes
|
|
undef - no osimage names
|
|
Globals:
|
|
none
|
|
Error:
|
|
Example:
|
|
my @imagenames=xCAT::TableUtils->getimagenames(\@nodes);
|
|
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
sub getimagenames()
|
|
{
|
|
my ($class, $nodes) = @_;
|
|
my @nodelist = @$nodes;
|
|
my $nodetab = xCAT::Table->new('nodetype');
|
|
my $images =
|
|
$nodetab->getNodesAttribs(\@nodelist, [ 'node', 'provmethod', 'profile' ]);
|
|
my @imagenames;
|
|
foreach my $node (@nodelist)
|
|
{
|
|
my $imgname;
|
|
if ($images->{$node}->[0]->{provmethod})
|
|
{
|
|
$imgname = $images->{$node}->[0]->{provmethod};
|
|
}
|
|
elsif ($images->{$node}->[0]->{profile})
|
|
{
|
|
$imgname = $images->{$node}->[0]->{profile};
|
|
}
|
|
|
|
# if the node has an image
|
|
if ($imgname) {
|
|
if (!grep(/^$imgname$/, @imagenames)) # not already on the list
|
|
{
|
|
push @imagenames, $imgname; # add to the array
|
|
}
|
|
}
|
|
}
|
|
$nodetab->close;
|
|
return @imagenames;
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
|
|
=head3 updatenodegroups
|
|
Update groups attribute for the specified node
|
|
|
|
Arguments:
|
|
node
|
|
tabhd: the handler of 'nodelist' table,
|
|
groups: the groups attribute need to be merged.
|
|
Can be an array or string.
|
|
Globals:
|
|
none
|
|
Error:
|
|
Example:
|
|
xCAT::TableUtils->updatenodegroups($node, $tab, $groups);
|
|
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
sub updatenodegroups {
|
|
my ($class, $node, $tabhd, $groups) = @_;
|
|
if (!$groups) {
|
|
$groups = $tabhd;
|
|
$tabhd = xCAT::Table->new('nodelist');
|
|
unless ($tabhd) {
|
|
xCAT::MsgUtils->message("E", " Could not read the nodelist table\n");
|
|
return;
|
|
}
|
|
}
|
|
my ($ent) = $tabhd->getNodeAttribs($node, ['groups']);
|
|
my @list = ();
|
|
if (defined($ent) and $ent->{groups}) {
|
|
push @list, split(/,/, $ent->{groups});
|
|
}
|
|
if (ref($groups) eq 'ARRAY') {
|
|
push @list, @$groups;
|
|
} else {
|
|
push @list, split(/,/, $groups);
|
|
}
|
|
my %saw;
|
|
@saw{@list} = ();
|
|
@list = keys %saw;
|
|
$tabhd->setNodeAttribs($node, { groups => join(",", @list) });
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
|
|
=head3 rmnodegroups
|
|
remove groups from the group attribute for the specified node
|
|
|
|
Arguments:
|
|
node
|
|
tabhd: the handler of 'nodelist' table,
|
|
groups: the groups that need to be removed.
|
|
Can be an array or string.
|
|
Globals:
|
|
none
|
|
Error:
|
|
Example:
|
|
xCAT::TableUtils->rmnodegroups($node, $tab, $groups);
|
|
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
sub rmnodegroups {
|
|
my ($class, $node, $tabhd, $groups) = @_;
|
|
my ($ent) = $tabhd->getNodeAttribs($node, ['groups']);
|
|
my @definedgroups;
|
|
my @removegroups;
|
|
my @newgroups;
|
|
if (defined($ent) and $ent->{groups}) {
|
|
push @definedgroups, split(/,/, $ent->{groups});
|
|
}
|
|
if (ref($groups) eq 'ARRAY') {
|
|
push @removegroups, @$groups;
|
|
} else {
|
|
push @removegroups, split(/,/, $groups);
|
|
}
|
|
|
|
# take out any groups that match the input list of groups to remove
|
|
foreach my $dgrp (@definedgroups) {
|
|
if (grep(/^$dgrp$/, @removegroups)) { # is the group to be removed
|
|
next;
|
|
} else { # keep this group
|
|
push @newgroups, $dgrp;
|
|
}
|
|
}
|
|
my %saw;
|
|
@saw{@newgroups} = ();
|
|
@newgroups = keys %saw;
|
|
|
|
$tabhd->setNodeAttribs($node, { groups => join(",", @newgroups) });
|
|
}
|
|
|
|
1;
|