xcat-core/xCAT-server/lib/xcat/plugins/snmove.pm
2012-08-09 04:07:40 +00:00

2230 lines
61 KiB
Perl

# IBM(c) 2010 EPL license http://www.eclipse.org/legal/epl-v10.html
#-------------------------------------------------------
=head1
xCAT plugin package to handle the snmove command
=cut
#-------------------------------------------------------
package xCAT_plugin::snmove;
BEGIN
{
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
}
use lib "$::XCATROOT/lib/perl";
use strict;
use Sys::Hostname;
use File::Basename;
use File::Path;
use xCAT::Table;
use xCAT::Utils;
use xCAT::TableUtils;
use xCAT::ServiceNodeUtils;
use xCAT::NetworkUtils;
use xCAT::MsgUtils;
use xCAT::SvrUtils;
use Getopt::Long;
use xCAT::NodeRange;
#use Data::Dumper;
1;
#-------------------------------------------------------
=head3 handled_commands
Return list of commands handled by this plugin
=cut
#-------------------------------------------------------
sub handled_commands
{
return {snmove => "snmove",};
}
#-------------------------------------------------------
=head3 preprocess_request
Preprocess the command
=cut
#-------------------------------------------------------
sub preprocess_request
{
my $request = shift;
my $callback = shift;
my $sub_req = shift;
my $command = $request->{command}->[0];
my $args = $request->{arg};
#if already preprocessed, go straight to process_request
if ( (defined($request->{_xcatpreprocessed}))
&& ($request->{_xcatpreprocessed}->[0] == 1))
{
return [$request];
}
# let process_request handle it
my $reqcopy = {%$request};
$reqcopy->{_xcatpreprocessed}->[0] = 1;
return [$reqcopy];
}
#-------------------------------------------------------
=head3 process_request
Process the command
=cut
#-------------------------------------------------------
sub process_request
{
my $request = shift;
my $callback = shift;
my $sub_req = shift;
my $command = $request->{command}->[0];
my $args = $request->{arg};
my $error = 0;
# parse the options
@ARGV = ();
if ($args)
{
@ARGV = @{$args};
}
Getopt::Long::Configure("bundling");
Getopt::Long::Configure("no_pass_through");
if (
!GetOptions(
'h|help' => \$::HELP,
'v|version' => \$::VERSION,
's|source=s' => \$::SN1, # source SN akb MN
'S|sourcen=s' => \$::SN1N, # source SN akb node
'd|dest=s' => \$::SN2, # dest SN akb MN
'D|destn=s' => \$::SN2N, # dest SN akb node
'l|liteonly' => \$::SLonly, # update statelite only!
'P|postscripts=s' => \$::POST, # postscripts to be run
'i|ignorenodes' => \$::IGNORE,
'V|verbose' => \$::VERBOSE,
)
)
{
&usage($callback);
return 1;
}
# display the usage if -h or --help is specified
if ($::HELP)
{
&usage($callback);
return 0;
}
# display the version statement if -v or --verison is specified
if ($::VERSION)
{
my $rsp = {};
$rsp->{data}->[0] = xCAT::Utils->Version();
$callback->($rsp);
return 0;
}
if (($::IGNORE) && ($::POST))
{
my $rsp = {};
$rsp->{data}->[0] =
"-P and -i flags cannot be specified at the same time.\n";
$callback->($rsp);
return 1;
}
if (@ARGV > 1)
{
my $rsp = {};
$rsp->{data}->[0] = "Too many paramters.\n";
$callback->($rsp);
&usage($callback);
return 1;
}
if ((@ARGV == 0) && (!$::SN1))
{
my $rsp = {};
$rsp->{data}->[0] =
"A node range or the source service node must be specified.\n";
$callback->($rsp);
&usage($callback);
return 1;
}
if (!$::SLonly) {
my $rsp;
push @{$rsp->{data}}, "Moving nodes to their backup service nodes.\n";
xCAT::MsgUtils->message("I", $rsp, $callback);
}
my $nimprime = xCAT::InstUtils->getnimprime();
chomp $nimprime;
#
# get the list of nodes
# - either from the command line or by checking which nodes are
# managed by the servicenode (SN1)
#
my @nodes = ();
if (@ARGV == 1)
{
my $nr = $ARGV[0];
@nodes = noderange($nr);
if (nodesmissed)
{
my $rsp = {};
$rsp->{data}->[0] =
"Invalid nodes in noderange:" . join(',', nodesmissed);
$callback->($rsp);
return 1;
}
}
else
{
# get all the nodes that use SN1 as the primary service nodes
my $pn_hash = xCAT::ServiceNodeUtils->getSNandNodes();
foreach my $snlist (keys %$pn_hash)
{
if (($snlist =~ /^$::SN1$/) || ($snlist =~ /^$::SN1\,/))
{
push(@nodes, @{$pn_hash->{$snlist}});
}
}
}
#
# make sure all the nodes are resolvable
#
foreach my $n (@nodes)
{
my $packed_ip = xCAT::NetworkUtils->getipaddr($n);
if (!$packed_ip)
{
my $rsp;
$rsp->{data}->[0] = "Could not resolve node \'$n\'.\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 1;
}
}
#
# get the node object definitions
#
my %objtype;
my %nodehash;
foreach my $o (@nodes)
{
$objtype{$o} = 'node';
}
my %nhash = xCAT::DBobjUtils->getobjdefs(\%objtype, $callback);
if (!(%nhash))
{
my $rsp;
push @{$rsp->{data}}, "Could not get xCAT object definitions.\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 1;
}
# are we dealing with AIX or Linux ?
# can't use isAIX since the MN could be Linux in mixed cluster
$::islinux = 0;
$::isaix = 0;
foreach my $node (@nodes)
{
if ($nhash{$node}{os} eq "AIX")
{
$::isaix++;
}
else
{
$::islinux++;
}
}
if ($::islinux && $::isaix)
{
my $rsp;
push @{$rsp->{data}},
"This command does not support a mix of AIX and Linux nodes.\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 1;
}
if ($::SLonly && $::islinux)
{
my $rsp;
push @{$rsp->{data}},
"The '-l' option is not supported for Linux nodes.\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 1;
}
#
# get the nimtype for AIX nodes (diskless or standalone)
#
my %nimtype;
if ($::isaix)
{
# need to check the nimimage table to find the nimtype
my $nimtab = xCAT::Table->new('nimimage', -create => 1);
if ($nimtab)
{
foreach my $node (@nodes)
{
my $provmethod = $nhash{$node}{'provmethod'};
# get the nimtype
my $ref =
$nimtab->getAttribs({imagename => $provmethod}, 'nimtype');
if ($ref)
{
$nimtype{$node} = $ref->{'nimtype'};
}
}
}
}
#
# get the backup sn for each node
#
my @servlist; # list of new service nodes
my %newsn;
my $nodehash;
if ($::SN2)
{ # we have the backup for each node from cmd line
foreach my $n (@nodes)
{
$newsn{$n} = $::SN2;
}
push(@servlist, $::SN2);
}
else
{
# check the 2nd value of the servicenode attr
foreach my $node (@nodes)
{
if ($nhash{$node}{'servicenode'})
{
my @sn = split(',', $nhash{$node}{'servicenode'});
# if ((scalar(@sn) > 2) && (xCAT::Utils->isAIX()))
if ((scalar(@sn) > 2) && ($::isaix))
{
my $rsp = {};
$rsp->{error}->[0] =
"The service node attribute cannot have more than two values.";
$callback->($rsp);
}
if ($sn[1])
{
$newsn{$node} = $sn[1];
if (!grep(/^$sn[1]$/, @servlist))
{
push(@servlist, $sn[1]);
}
}
}
if (!$newsn{$node})
{
my $rsp = {};
$rsp->{error}->[0] =
"Could not determine a backup service node for node $node.";
$callback->($rsp);
$error++;
}
}
}
if ($error)
{
return 1;
}
#
# get the new xcatmaster for each node
#
my %newxcatmaster;
if ($::SN2N)
{ # we have the xcatmaster for each node from cmd line
foreach my $n (@nodes)
{
$newxcatmaster{$n} = $::SN2N;
}
}
else
{
# try to calculate the xcatmaster value for each node
# get all the interfaces from each SN
# $sni{$SN}= list of ip
my $s = &getSNinterfaces(\@servlist, $callback, $sub_req);
my %sni = %$s;
# get the network info for each node
# $nethash{nodename}{networks attr name} = value
my %nethash = xCAT::DBobjUtils->getNetwkInfo(\@nodes);
# determine the xcatmaster value for the new SN
foreach my $node (@nodes)
{
# get the node ip
# or use getNodeIPaddress
my $nodeIP = xCAT::NetworkUtils->getipaddr($node);
chomp $nodeIP;
# get the new SN for the node
my $mySN = $newsn{$node};
# check each interface on the service node
foreach my $IP (@{$sni{$mySN}})
{
# if IP is in nodes subnet then thats the xcatmaster
if (
xCAT::NetworkUtils->ishostinsubnet(
$IP,
$nethash{$node}{mask},
$nethash{$node}{net}
)
)
{
# get the short hostname
my $xcatmaster = xCAT::NetworkUtils->gethostname($IP);
$xcatmaster =~ s/\..*//;
# add the value to the hash
$newxcatmaster{$node} = $xcatmaster;
last;
}
}
if (!$newxcatmaster{$node})
{
my $rsp = {};
$rsp->{error}->[0] =
"Could not determine an xcatmaster value for node $node.";
$callback->($rsp);
$error++;
}
}
}
if ($error)
{
return 1;
}
#
# determine the new node attribute values
#
my %sn_hash;
my $old_node_hash = {};
my $index = 0;
foreach my $node (@nodes)
{
my $sn1;
my $sn1n;
my $sn1n_ip;
# get current xcatmaster
if ($::SN1N)
{ # use command line value
$sn1n = $::SN1N;
}
elsif ($nhash{$node}{'xcatmaster'})
{ # use xcatmaster attr
$sn1n = $nhash{$node}{'xcatmaster'};
}
if ($sn1n)
{
my @ret = xCAT::NetworkUtils::toIP($sn1n);
if ($ret[0]->[0] == 0)
{
$sn1n_ip = $ret[0]->[1];
}
}
# get the servicenode values
my @sn_a;
my $snlist = $nhash{$node}{'servicenode'};
@sn_a = split(',', $snlist);
# get current servicenode
if ($::SN1)
{
# current SN from the command line
$sn1 = $::SN1;
}
else
{
# current SN from node attribute
$sn1 = $sn_a[0];
}
# switch the servicenode attr list
my @sn_temp = grep(!/^$newsn{$node}$/, @sn_a);
unshift(@sn_temp, $newsn{$node});
my $t = join(',', @sn_temp);
$sn_hash{$node}{objtype} = 'node';
# set servicenode and xcatmaster attr
$sn_hash{$node}{'servicenode'} = $t;
$sn_hash{$node}{'xcatmaster'} = $newxcatmaster{$node};
$old_node_hash->{$node}->{'oldsn'} = $sn1;
$old_node_hash->{$node}->{'oldmaster'} = $sn1n;
# set tftpserver
my $tftp = $nhash{$node}{'tftpserver'};
if ($tftp)
{
if ($sn1n && ($tftp eq $sn1n))
{
$sn_hash{$node}{'tftpserver'} = $newxcatmaster{$node};
}
elsif ($sn1n_ip && ($tftp eq $sn1n_ip))
{
$sn_hash{$node}{'tftpserver'} = $newxcatmaster{$node};
}
}
# set nfsserver
my $nfs = $nhash{$node}{'nfsserver'};
if ($nfs)
{
if ($sn1n && ($nfs eq $sn1n))
{
$sn_hash{$node}{'nfsserver'} = $newxcatmaster{$node};
}
elsif ($sn1n_ip && ($nfs eq $sn1n_ip))
{
$sn_hash{$node}{'nfsserver'} = $newxcatmaster{$node};
}
}
#set monserver ( = "servicenode,xcatmaster" )
my $mon = $nhash{$node}{'monserver'};
if ($mon) # if it is currently set
{
my @tmp_a = split(',', $mon);
if (scalar(@tmp_a) < 2) # it must have two values
{
my $rsp;
push @{$rsp->{data}},
"The current value of the monserver attribute is not valid. It will not be reset.\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
}
else
{
# if the first value is the current service node then change it
if ($tmp_a[0] eq $sn1)
{
$sn_hash{$node}{'monserver'} =
"$newsn{$node},$newxcatmaster{$node}";
}
}
}
} # end - foreach node
# check the sharedinstall attr
my $sharedinstall=xCAT::TableUtils->get_site_attribute('sharedinstall');
chomp $sharedinstall;
if (!$sharedinstall) {
$sharedinstall="no";
}
# handle the statelite update for sharedinstall=no
# - not using a shared files system
my %SLmodhash;
my %LTmodhash;
if ( ($::SLonly) && ($sharedinstall eq "sns") )
{
my $rsp;
push @{$rsp->{data}}, "The liteonly option is not valaid when using a shared file system across service nodes.\n";
xCAT::MsgUtils->message("I", $rsp, $callback);
return 1;
}
if ( ($::isaix) && ($sharedinstall eq "no") )
{
#
# try to rsync statelite dirs from old SN to new SN
# - only if old SN is listed in the tables!
#
if ($::VERBOSE)
{
my $rsp;
push @{$rsp->{data}},
"Attempting the synchronization of statelite files.\n";
xCAT::MsgUtils->message("I", $rsp, $callback);
}
#
# handle statelite table
#
my $statetab = xCAT::Table->new('statelite', -create => 1);
# get hash of entries???
my $recs = $statetab->getAllEntries;
my $statemnt;
my $server;
my $dir;
my $item = 0;
my $id = 0;
my %donehash;
# for each entry
foreach my $line (@$recs)
{
$statemnt = $line->{statemnt};
($server, $dir) = split(/:/, $statemnt);
# see what nodes this entry applies to
my @nodeattr = &noderange($line->{node}, 0);
chomp $server;
my @donelist; # list of indices of old/new SN pairs
# the server and dir could potentially be different for each node
foreach my $n (@nodes)
{
# if the node is not in the noderange for this
# entry then skip it
if (!grep(/$n/, @nodeattr))
{
next;
}
# check for the server
if (grep /\$/, $server)
{
my $serv =
xCAT::SvrUtils->subVars($server, $n, 'server', $callback);
$server = $serv;
# note: if a variable is used in the entry then it
# does not have to be updated.
}
else
{
# if the $server value was the old SN hostname
# then we need to
# update the statelite table with the new SN name
$item++;
my $stmnt = "$sn_hash{$n}{'xcatmaster'}:$dir";
$SLmodhash{$item}{'statemnt'} = $stmnt;
$SLmodhash{$item}{'node'} = $n;
}
# check for the directory
if (grep /\$|#CMD/, $dir)
{
$dir = xCAT::SvrUtils->subVars($dir, $n, 'dir', $callback);
$dir =~ s/\/\//\//g;
}
# we only want to sync the subdir for this node
# ex. if dir = /nodedata then we sync /nodedata/compute03
my $dodir;
my $shorthost;
# just to be sure we have the short name
($shorthost = $n) =~ s/\..*$//;
if ($dir =~ /\/$/)
{
$dodir = "$dir$shorthost";
} else {
$dodir = "$dir/$shorthost";
}
# see if the server in the table matches the nodes SN
if ($server eq $old_node_hash->{$n}->{'oldmaster'})
{
# see if we did this sync already
my $foundit = 0;
foreach my $i (keys %donehash)
{
# if the server and dir are the same then
# we already did it
if (
($dodir eq $donehash{$i}{dir})
&& ($server eq $donehash{$i}{oldXM})
&& ($donehash{$i}{newXM} eq
$sn_hash{$n}{'xcatmaster'})
)
{
$foundit++;
}
}
# ok - just skip to the next node
if ($foundit)
{
next;
}
if ($::VERBOSE)
{
my $rsp;
push @{$rsp->{data}},
"Synchronizing $dodir to $sn_hash{$n}{'xcatmaster'}\n";
xCAT::MsgUtils->message("I", $rsp, $callback);
}
my $todir = dirname($dodir);
# do rsync of file/dir
my $synccmd =
qq~/usr/bin/rsync -arlHpEAogDz $dodir $newsn{$n}:$todir 2>&1~;
if ($::VERBOSE) {
my $rsp;
push @{$rsp->{data}}, "On $old_node_hash->{$n}->{'oldsn'}: Running: \'$synccmd\'\n";
xCAT::MsgUtils->message("I", $rsp, $callback);
}
my $output =
xCAT::InstUtils->xcmd($callback, $sub_req, "xdsh",
$old_node_hash->{$n}->{'oldsn'},
$synccmd, 0);
if ($::RUNCMD_RC != 0)
{
my $rsp;
push @{$rsp->{data}},
"Could not sync statelite \'$dodir\'.";
push @{$rsp->{data}}, "$output\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
$error++;
}
else
{
$id++;
$donehash{$id}{oldXM} =
$old_node_hash->{$n}->{'oldmaster'};
$donehash{$id}{dir} = $dodir;
$donehash{$id}{newXM} = $sn_hash{$n}{'xcatmaster'};
}
} # end if servers match
} # end - foreach node
} # end for each line in statelite table
# done with statelite table
$statetab->close();
# if only statelite sync is required then return now
if ($::SLonly)
{
return 0;
}
} # end sync statelite
my $rsp;
push @{$rsp->{data}}, "Setting new values in the xCAT database.\n";
xCAT::MsgUtils->message("I", $rsp, $callback);
#
# make updates to statelite table
#
if ( ($::isaix) && ($sharedinstall eq "no") )
{
my $statetab = xCAT::Table->new('statelite', -create => 1);
# for each key in SLmodhash - update the statelite table
foreach my $item (keys %SLmodhash)
{
my $node = $SLmodhash{$item}{'node'};
my $statemnt = $SLmodhash{$item}{'statemnt'};
$statetab->setAttribs({'node' => $node}, {'statemnt' => $statemnt});
}
# done with statelite table
$statetab->close();
}
# update the node definitions #1
if (keys(%sn_hash) > 0)
{
# update the node definition
if (xCAT::DBobjUtils->setobjdefs(\%sn_hash) != 0)
{
my $rsp;
push @{$rsp->{data}}, "Could not update xCAT node definitions.\n";
xCAT::MsgUtils->message("E", $rsp, $::callback);
$error++;
}
}
#
# handle conserver
#
my %sn_hash1;
foreach my $node (@nodes)
{
if ( ($nhash{$node}{'conserver'})
and
($nhash{$node}{'conserver'} eq $old_node_hash->{$node}->{'oldsn'}))
{
$sn_hash1{$node}{'conserver'} = $newsn{$node};
$sn_hash1{$node}{objtype} = 'node';
}
}
# update the node definition #2
if (keys(%sn_hash1) > 0)
{
if (xCAT::DBobjUtils->setobjdefs(\%sn_hash1) != 0)
{
my $rsp;
push @{$rsp->{data}}, "Could not update xCAT node definitions.\n";
xCAT::MsgUtils->message("E", $rsp, $::callback);
$error++;
}
}
#
# handle the statelite update for the sharedinstall=sns case
# - using a shared file system across all service nodes
# - must be done AFTER node def is updated!
#
if ( ($::isaix) && ($sharedinstall eq "sns") ){
my $s = &sfsSLconfig(\@nodes, \%nhash, \%sn_hash, $old_node_hash, $nimprime, $callback, $sub_req);
}
# TBD - handle sharedinstall =all case ????
# run makeconservercf
my @nodes_con = keys(%sn_hash1);
if (@nodes_con > 0)
{
my $rsp = {};
$rsp->{data}->[0] = "Running makeconservercf " . join(',', @nodes_con);
$callback->($rsp);
my $ret =
xCAT::Utils->runxcmd(
{
command => ['makeconservercf'],
node => \@nodes_con,
},
$sub_req, 0, 1
);
$callback->({data => $ret});
}
#
# restore .client_data files on the new SN
#
if ( ($::isaix) && ($sharedinstall eq "sns") ){
# first get the shared_root locations for each SN and osimage
my $nimtab = xCAT::Table->new('nimimage');
my %SRloc;
foreach my $n (@nodes) {
my $osimage = $nhash{$n}{'provmethod'};
my ($sn, $junk) = split(/,/, $nhash{$n}{'servicenode'});
# $sn is name of SN as known by management node
if (!$SRloc{$sn}{$osimage}) {
my $SRn = $nimtab->getAttribs({'imagename' => $osimage}, 'shared_root');
my $SRname=$SRn->{shared_root};
if ($SRname) {
my $srloc = xCAT::InstUtils->get_nim_attr_val($SRname, 'location', $callback, $nimprime, $sub_req);
$SRloc{$sn}{$osimage}=$srloc;
}
}
}
$nimtab->close();
# now try to restore any backup client data
# for each service node
foreach my $s (keys %SRloc) {
# for each osimage on that SN
foreach my $osi (keys %{$SRloc{$s}}) {
# set the names of the .client_data and backup directories
my $sloc = $SRloc{$s}{$osi};
# ex. /install/nim/shared_root/71Bdskls_shared_root
my $cdloc = "$sloc/etc/.client_data";
my $snbk = "$s" . "_" . "$osi";
my $bkloc = "$sloc/$snbk/.client_data";
# get a list of files from the backup dir
my $rcmd = qq~/usr/bin/ls $bkloc 2>/dev/null~;
my $rlist = xCAT::InstUtils->xcmd($callback, $sub_req, "xdsh", $s, $rcmd, 0);
if ($::RUNCMD_RC != 0)
{
my $rsp;
push @{$rsp->{data}}, "Could not list contents of $bkloc.\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
$error++;
}
# restore file on node by node basis
# we don't want all the files!
# - just the ones we are moving
foreach my $nd (@nodes) {
$nd =~ s/\..*$//;
# for each file in $bkloc
my $filestring = "";
foreach my $f ( split(/\n/, $rlist) ){
my $junk;
my $file;
if ($f =~ /:/) {
($junk, $file) = split(/:/, $f);
}
$file =~ s/\s*//g; # remove blanks
# if file contains node name then copy it
if ($file =~ /$nd/) {
$filestring .= "$bkloc/$file ";
}
}
my $ccmd=qq~/usr/bin/cp -p -r $filestring $cdloc 2>/dev/null~;
my $output = xCAT::InstUtils->xcmd($callback, $sub_req, "xdsh", $s, $rcmd, 0);
if ($::RUNCMD_RC != 0)
{
my $rsp;
push @{$rsp->{data}}, "Could not copy files to $cdloc.\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
$error++;
}
}
}
}
}
#
# - retarget the iscsi dump device to the new server for the nodes
#
if ((!$::IGNORE) && ($::isaix) && ($sharedinstall eq "sns")) {
if (&dump_retarget($callback, \@nodes, $sub_req) != 0)
{
my $rsp;
push @{$rsp->{data}}, "One or more errors occured while attemping to re-target the dump device on cluster nodes.\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
$error++;
}
}
#
# Run niminit on AIX diskful nodes
#
if (!$::IGNORE) # unless the user does not want us to touch the node
{
if ($::isaix)
{
#if the node is aix and the type is standalone
foreach my $node (@nodes)
{
# if this is a standalone node then run niminit
if (($nimtype{$node}) && ($nimtype{$node} eq 'standalone'))
{
if ($::VERBOSE)
{
my $rsp;
push @{$rsp->{data}},"Running niminit on $node.\n";
xCAT::MsgUtils->message("I", $rsp, $callback);
}
my $nimcmd =
qq~/usr/sbin/niminit -a name=$node -a master=$newsn{$node} >/dev/null 2>&1~;
my $out =
xCAT::InstUtils->xcmd($callback, $sub_req, "xdsh", $node,
$nimcmd, 0);
if ($::RUNCMD_RC != 0)
{
my $rsp;
push @{$rsp->{data}},
"Could not run niminit on node $node.\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
$error++;
}
}
}
}
}
# for Linux system only
if ($::islinux)
{
#tftp, dhcp and nfs (site.disjointdhcps should be set to 1)
# get a list of nodes for each provmethod
my %nodeset_hash;
foreach my $node (@nodes)
{
my $provmethod = $nhash{$node}{'provmethod'};
if ($provmethod)
{
if (!grep(/^$node$/, @{$nodeset_hash{$provmethod}}))
{
push(@{$nodeset_hash{$provmethod}}, $node);
}
}
}
# run the nodeset command
foreach my $provmethod (keys(%nodeset_hash))
{
# need a node list to send to nodeset
my @nodeset_nodes = @{$nodeset_hash{$provmethod}};
if ( ($provmethod eq 'netboot')
|| ($provmethod eq 'install')
|| ($provmethod eq 'statelite'))
{
my $ret =
xCAT::Utils->runxcmd(
{
command => ['nodeset'],
node => \@nodeset_nodes,
arg => [$provmethod],
},
$sub_req, 0, 1
);
my $rsp;
$rsp->{data}=$ret;
xCAT::MsgUtils->message("I", $rsp, $callback);
if ($::RUNCMD_RC != 0)
{
$error++;
}
}
else
{
my $ret =
xCAT::Utils->runxcmd(
{
command => ['nodeset'],
node => \@nodeset_nodes,
arg => ["osimage=$provmethod"],
},
$sub_req, 0, 1
);
my $rsp;
$rsp->{data}=$ret;
xCAT::MsgUtils->message("I", $rsp, $callback);
if ($::RUNCMD_RC != 0)
{
$error++;
}
}
}
} # end - for Linux system only
#
# update the /etc/xcatinfo files on the nodes
# switch to the new server name
#
if (!$::IGNORE)
{
if ($::isaix)
{
if ($::VERBOSE)
{
my $rsp;
push @{$rsp->{data}}, "Updating the /etc/xcatinfo files.\n";
xCAT::MsgUtils->message("I", $rsp, $callback);
}
foreach my $node (@nodes)
{
# may need to reorg this
# could organized into set of nodes for each new xcatmaster
# then run runxcmd for that set of nodes
my $IP = xCAT::NetworkUtils->getipaddr($newxcatmaster{$node});
chomp $IP;
my $cmd = qq~echo "XCATSERVER=$IP" > /etc/xcatinfo~;
my @nlist;
push(@nlist, $node);
my $ret =
xCAT::Utils->runxcmd(
{
command => ['xdsh'],
node => \@nlist,
arg => ["$cmd"],
},
$sub_req, 0, 1
);
if ($::RUNCMD_RC != 0)
{
$error++;
}
}
} # end if isaix
} # end of not ignore
if (!$::IGNORE)
{
#
# for both AIX and Linux systems
# setup the default gateway if the network.gateway=xcatmaster
# for the node
#
my %nethash;
my %ipmap = ();
my %gwhash = ();
my $nwtab = xCAT::Table->new("networks");
if ($nwtab)
{
my @tmp1 =
$nwtab->getAllAttribs(('net', 'mask', 'gateway', 'mgtifname'));
if (@tmp1 && (@tmp1 > 0))
{
foreach my $nwitem (@tmp1)
{
my $gw = $nwitem->{'gateway'};
if (!$gw)
{
next;
}
chomp $gw;
if ($gw ne '<xcatmaster>')
{
next;
}
#now only handle the networks that has <xcatmaster>
# as the gateway
my $NM = $nwitem->{'mask'};
my $net = $nwitem->{'net'};
my $ifname = $nwitem->{'mgtifname'};
chomp $NM;
chomp $net;
chomp $ifname;
# for each node - get the network info
foreach my $node (@nodes)
{
# get, check, split the node IP
my $IP = xCAT::NetworkUtils->getipaddr($node);
chomp $IP;
# check the entries of the networks table
# - if the bitwise AND of the IP and the netmask
# gives you
# the "net" name then that is the entry you want.
if (xCAT::NetworkUtils->ishostinsubnet($IP, $NM, $net))
{
my $newmaster = $newxcatmaster{$node};
my $newmasterIP;
if (exists($ipmap{$newmaster}))
{
$newmasterIP = $ipmap{$newmaster};
}
else
{
$newmasterIP =
xCAT::NetworkUtils->getipaddr($newmaster);
chomp($newmasterIP);
$ipmap{$newmaster} = $newmasterIP;
}
$nethash{$node}{'gateway'} = $newmasterIP;
$nethash{$node}{'net'} = $net;
$nethash{$node}{'mask'} = $NM;
$nethash{$node}{'mgtifname'} = $ifname;
if ($newmasterIP)
{
if (exists($gwhash{$newmasterIP}))
{
my $pa = $gwhash{$newmasterIP};
push(@$pa, $node);
}
else
{
$gwhash{$newmasterIP} = [$node];
}
}
}
}
}
}
}
if (keys(%gwhash) > 0)
{
my $rsp;
$rsp->{data}->[0] = "Checking the default routes on the nodes.";
xCAT::MsgUtils->message("I", $rsp, $callback);
}
# for each new xcatmaster ip (gateway)
foreach my $gw (keys %gwhash)
{
# for each node that is moved to this new gateway
foreach my $nd ( @{$gwhash{$gw}} ) {
my $cmd = "route add default gw"; # for linux
if ($::isaix)
{
# we need to make sure we have a default gateway set
# to the new SN - however we do not want to add
# an additional default gateway and we don't
# want to do anything to change what the user
# may have set up
# SO - just see if the old SN is the only default set
# and if so then change it to the new gw (SN)
my $oldgwip = xCAT::NetworkUtils->getipaddr($old_node_hash->{$nd}->{'oldmaster'});
# get the ouptut of "netstat -rn"
my $netcmd = qq~netstat -rn~;
my $netout = xCAT::InstUtils->xcmd($callback, $sub_req, "xdsh", $nd, $netcmd, 0);
my $foundold;
my $foundnew;
# see what default routes are set
foreach my $l (split(/\n/, $netout)) {
my $line;
my $junk;
if ($l =~ /:/) {
($junk, $line) = split(/:/, $l);
} else {
$line = $l;
}
my ($dest, $IP, $junk) = split(" ", $line);
if ($dest eq 'default') {
if ( $IP eq $oldgwip) {
$foundold++;
}
if ( $IP eq $gw) {
$foundnew++;
}
} else {
next;
}
} # end foreach
# decide if we need to change default gw
if ($foundold && !$foundnew) {
$cmd = "route change default";
} else {
$cmd = "";
}
}
if ($cmd )
{
my $ret =
xCAT::Utils->runxcmd(
{
command => ['xdsh'],
node => $gwhash{$gw},
arg => ["-v", "$cmd $gw"],
},
$sub_req, -1, 1
);
if ($::RUNCMD_RC != 0)
{
my $rsp;
push @{$rsp->{data}}, $ret;
push @{$rsp->{data}}, "Could not set default route.\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
$error++;
}
}
} # end foreach node
} # end for each new gw
} # if not ignore nodes
#
# run the bootlist command
#
if (!$::IGNORE)
{
if ($::isaix)
{
# if ($::VERBOSE)
{
my $rsp;
push @{$rsp->{data}}, "Updating the bootlist.\n";
xCAT::MsgUtils->message("I", $rsp, $callback);
}
my %nethash = xCAT::DBobjUtils->getNetwkInfo(\@nodes);
foreach my $nd (@nodes)
{
# get the device name to use with the bootlist cmd
my $nimcmd = qq~netstat -in~;
my $nimout = xCAT::InstUtils->xcmd($callback, $sub_req, "xdsh", $nd, $nimcmd,0);
my $myip = xCAT::NetworkUtils->getipaddr($nd);
chomp $myip;
my $intname;
foreach my $l (split(/\n/,$nimout))
{
my $line;
my $junk;
if ($l =~ /:/) {
($junk, $line) = split(/:/, $l);
} else {
$line = $l;
}
my ($name, $junk1, $junk, $IP, $junk3) = split(" ", $line);
chomp $IP;
if ($IP eq $myip)
{
$intname =$name;
last;
}
}
my $devicename;
if ($intname =~ /hf/) {
$intname =~ s/hf/hfi/g;
} elsif ($intname =~ /en/) {
$intname =~ s/en/ent/g;
} elsif ($intname =~ /et/) {
my $index = $intname =~ s/et//g;
$intname =~ s/et/ent/g;
}
$devicename = $intname;
# need node gateway
my $gateway = $nethash{$nd}{'gateway'};
# the boot server is the new xcatmaster value
my $snIP = xCAT::NetworkUtils->getipaddr($newxcatmaster{$nd});
# point to the new server
my $blcmd = qq~/usr/bin/bootlist -m normal $devicename gateway=$gateway bserver=$snIP client=$myip ~;
my $output = xCAT::InstUtils->xcmd($callback, $sub_req, "xdsh", $nd, $blcmd, 0);
if ($::RUNCMD_RC != 0)
{
my $rsp;
push @{$rsp->{data}}, "Could not run \'$blcmd\' on node $nd.\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
$error++;
next;
}
}
}
}
# run postscripts to take care of syslog, ntp, and mkresolvconf
# - if they are included in the postscripts table
if (!$::IGNORE) # unless the user does not want us to touch the node
{
# get all the postscripts that should be run for the nodes
my $pstab = xCAT::Table->new('postscripts', -create => 1);
my $nodeposhash = {};
if ($pstab)
{
$nodeposhash =
$pstab->getNodesAttribs(\@nodes,
['postscripts', 'postbootscripts']);
}
else
{
my $rsp = {};
$rsp->{error}->[0] = "Cannot open postscripts table.\n";
$callback->($rsp);
return 1;
}
my $et =
$pstab->getAttribs({node => "xcatdefaults"},
'postscripts', 'postbootscripts');
my $defscripts = "";
my $defbootscripts = "";
if ($et)
{
$defscripts = $et->{'postscripts'};
$defbootscripts = $et->{'postbootscripts'};
}
my $user_posts;
if ($::POST)
{
$user_posts = $::POST;
}
my $pos_hash = {};
foreach my $node (@nodes)
{
foreach my $rec (@{$nodeposhash->{$node}})
{
my $scripts;
if ($rec)
{
$scripts = join(',',
$defscripts, $rec->{'postscripts'},
$defbootscripts, $rec->{'postbootscripts'});
}
else
{
$scripts = join(',', $defscripts, $defbootscripts);
}
my @tmp_a = split(',', $scripts);
# xCAT's default scripts to be run: syslog,
# setupntp, and mkresolvconf
my @valid_scripts;
if ( ($::isaix) && ($sharedinstall eq "sns") ){
@valid_scripts = ("syslog", "setupntp");
} else {
@valid_scripts = ("syslog", "setupntp", "mkresolvconf");
}
my $scripts1 = "";
if (($user_posts) && ($user_posts eq "all"))
{
$scripts1 = $scripts;
#run all the postscripts defined in the postscripts table
}
else
{
foreach my $s (@valid_scripts)
{
# if it was included in the original list then run it
if (grep(/^$s$/, @tmp_a))
{
if ($scripts1)
{
$scripts1 = "$scripts1,$s";
}
else
{
$scripts1 = $s;
}
}
}
#append the user given scripts
if ($user_posts)
{
if ($scripts1)
{
$scripts1 = "$scripts1,$user_posts";
}
else
{
$scripts1 = $user_posts;
}
}
}
if ($scripts1)
{
if (exists($pos_hash->{$scripts1}))
{
my $pa = $pos_hash->{$scripts1};
push(@$pa, $node);
}
else
{
$pos_hash->{$scripts1} = [$node];
}
}
}
}
my $rsp;
$rsp->{data}->[0] = "Running postscripts on the nodes.";
xCAT::MsgUtils->message("I", $rsp, $callback);
foreach my $scripts (keys(%$pos_hash))
{
my $pos_nodes = $pos_hash->{$scripts};
my $ret =
xCAT::Utils->runxcmd(
{
command => ['updatenode'],
node => $pos_nodes,
arg => ["-P", "$scripts", "-s"],
},
$sub_req, -1, 1
);
if ($::RUNCMD_RC != 0)
{
$error++;
}
my $rsp;
$rsp->{data} = $ret;
xCAT::MsgUtils->message("I", $rsp, $callback);
}
} # end -for both AIX and Linux systems
my $retcode = 0;
if ($error)
{
#my $rsp;
#push @{$rsp->{data}}, "One or more errors occurred while attempting to switch nodes to a new service node.\n";
#xCAT::MsgUtils->message("E", $rsp, $callback);
$retcode = 1;
}
#else
#{
# my $rsp;
# push @{$rsp->{data}}, "The nodes were successfully moved to the new service node.\n";
# xCAT::MsgUtils->message("I", $rsp, $callback);
#}
return $retcode;
}
#----------------------------------------------------------------------------
=head3 getSNinterfaces
Get a list of ip addresses for each service node in a list
Arguments:
list of servcie nodes
Returns:
1 - could not get list of ips
0 - ok
Globals:
none
Error:
none
Example:
my $sni = xCAT::InstUtils->getSNinterfaces(\@servlist);
Comments:
none
=cut
#-----------------------------------------------------------------------------
sub getSNinterfaces
{
my ($list, $callback, $sub_req) = @_;
my @snlist = @$list;
my %SNinterfaces;
# get all the possible IPs for the node I'm running on
my $ifcmd;
# if (xCAT::Utils->isAIX())
if ($::isaix)
{
$ifcmd = "/usr/sbin/ifconfig -a ";
}
else
{
$ifcmd = "/sbin/ip addr ";
}
foreach my $sn (@snlist)
{
my $SNIP;
my $result =
xCAT::InstUtils->xcmd($callback, $sub_req, "xdsh", $sn, $ifcmd, 0);
if ($::RUNCMD_RC != 0)
{
my $rsp = {};
$rsp->{data}->[0] =
"Could not get IP addresses from service node $sn.\n";
$callback->($rsp);
next;
}
foreach my $int (split(/\n/, $result))
{
if (!grep(/inet/, $int))
{
# only want line with "inet"
next;
}
$int =~ s/$sn:\s+//; # skip hostname from xdsh output
my @elems = split(/\s+/, $int);
if (xCAT::Utils->isLinux())
{
if ($elems[0] eq 'inet6')
{
#Linux IPv6 TODO, do not return IPv6 networks on
# Linux for now
next;
}
($SNIP, my $mask) = split /\//, $elems[1];
}
else
{
# for AIX
if ($elems[0] eq 'inet6')
{
$SNIP = $elems[1];
$SNIP =~ s/\/.*//; # ipv6 address 4000::99/64
$SNIP =~ s/\%.*//; # ipv6 address ::1%1/128
}
else
{
$SNIP = $elems[1];
}
}
chomp $SNIP;
push(@{$SNinterfaces{$sn}}, $SNIP);
}
}
return \%SNinterfaces;
}
#-----------------------------------------------------------------------------
sub usage
{
my $cb = shift;
my $rsp = {};
push @{$rsp->{data}},
"\nsnmove - Move xCAT compute nodes from one xCAT service node to a \nbackup service node.";
push @{$rsp->{data}}, "\nUsage: ";
push @{$rsp->{data}}, "\tsnmove [-h | --help ]\n";
push @{$rsp->{data}},
"\tsnmove noderange [-V] [-l|--liteonly] [[-d|--dest] sn2]\n\t\t[[-D|--destn] sn2n] [-i|--ignorenodes] \n\t\t[[-P|--postscripts] script1,script2...|all]\n";
push @{$rsp->{data}},
"\tsnmove [-V] [-l|--liteonly] -s|--source sn1 [[-S|--sourcen] sn1n]\n\t\t[[-d|--dest] sn2] [[-D|--dest ] sn2n]\n\t\t[-i|--ignorenodes][[-P|--postscripts] script1,script2...|all]";
push @{$rsp->{data}}, "\n";
push @{$rsp->{data}}, "\nWhere:";
push @{$rsp->{data}},
"\tsn1 is the hostname of the source service node as known by (facing) the management node.";
push @{$rsp->{data}},
"\tsn1n is the hostname of the source service node as known by (facing) the nodes.";
push @{$rsp->{data}},
"\tsn2 is the hostname of the destination service node as known by (facing) the management node.";
push @{$rsp->{data}},
"\tsn2n is the hostname of the destination service node as known by (facing) the nodes.";
push @{$rsp->{data}},
"\tscripts is a comma separated list of postscripts to be run on the nodes. 'all' means all the scripts defined in the postscripts table for each node are to be run.";
$cb->($rsp);
return 0;
}
#----------------------------------------------------------------------------
=head3 dump_retarget
Switches the iscsi dump target of nodes to a backup service node.
Arguments:
Returns:
0 - OK
1 - error
Usage: $ret = &dump_retarget($callback, \@nodelist, $sub_req);
=cut
#-----------------------------------------------------------------------------
sub dump_retarget
{
my $callback = shift;
my $nodelist = shift;
my $sub_req = shift;
my @nodes = @$nodelist;
my $error;
my $rsp;
push @{$rsp->{data}}, "Checking dump devices.\n";
xCAT::MsgUtils->message("I", $rsp, $callback);
# get provmethod and xcatmaster for each node
my $nrtab = xCAT::Table->new('noderes');
my $nttab = xCAT::Table->new('nodetype');
my $nrhash;
my $nthash;
if ($nrtab)
{
$nrhash = $nrtab->getNodesAttribs(\@nodes, ['xcatmaster', 'servicenode']);
}
else
{
my $rsp = {};
$rsp->{data}->[0] = "Can not open noderes table.\n";
xCAT::MsgUtils->message("E", $rsp, $callback, 1);
}
if ($nttab)
{
$nthash = $nttab->getNodesAttribs(\@nodes, ['provmethod']);
}
else
{
my $rsp = {};
$rsp->{data}->[0] = "Can not open nodetype table.\n";
xCAT::MsgUtils->message("E", $rsp, $callback, 1);
}
# get the network info for each node
# $nethash{nodename}{networks attr name} = value
my %nethash = xCAT::DBobjUtils->getNetwkInfo(\@nodes);
# get a list of nodes for each SNs and osimage combo
# - also a list of osimages.
my %SNosinodes;
my @image_names;
my %SNname;
foreach my $node (@nodes)
{
my $xmast = $nrhash->{$node}->[0]->{'xcatmaster'};
my ($snode, $junk) = (split /,/, $nrhash->{$node}->[0]->{'servicenode'});
my $osimage = $nthash->{$node}->[0]->{'provmethod'};
push(@{$SNosinodes{$xmast}{$osimage}}, $node);
if (!grep(/^$osimage$/, @image_names) ) {
push(@image_names, $osimage);
}
$SNname{$xmast}=$snode;
}
#
# get the image defs from the DB
#
my %imghash;
my %objtype;
# for each image
foreach my $m (@image_names)
{
$objtype{$m} = 'osimage';
}
my %imghash = xCAT::DBobjUtils->getobjdefs(\%objtype, $callback);
if (!(%imghash))
{
my $rsp;
push @{$rsp->{data}}, "Could not get xCAT osimage definitions.\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
}
# set the default port - todo - user could have set differently???
my $dump_port=32600;
# for each SN
foreach my $sn (keys %SNosinodes)
{
# get ip addr of SN as known by the node
# - sn is "xcatmaster"
chomp $sn;
my $SNip = xCAT::NetworkUtils->getipaddr($sn);
# this is "servicenode" value - get first in list
my ($xcatSNname, $junk) = (split /,/, $SNname{$sn});
# for each osimage needed for this SN
foreach my $osi (keys %{$SNosinodes{$sn}})
{
if (!$imghash{$osi}{'dump'}) {
next;
}
# get dump target and lun from nim dump res def
my %nimattrs;
my $dump_target;
my $dump_lunid;
my @attrs = ("dump_target", "dump_lunid");
my $na = &getnimattr($imghash{$osi}{'dump'}, \@attrs, $callback, $xcatSNname, $sub_req);
if ($na) {
%nimattrs = %{$na};
$dump_target = $nimattrs{dump_target};
$dump_lunid = $nimattrs{dump_lunid};
}
my $configdump;
if ($imghash{$osi}{'configdump'}) {
$configdump = $imghash{$osi}{'configdump'};
} else {
$configdump = "selective";
}
if ($::VERBOSE) {
# print values ??
# or cmd??
}
if (!$dump_target || !$dump_port || !$SNip || !$dump_lunid) {
my $rsp;
push @{$rsp->{data}}, "Could not re-target the dump device for the following nodes. \n@{$SNosinodes{$sn}{$osi}}\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
$error++;
next;
}
my @nodelist = @{$SNosinodes{$sn}{$osi}};
foreach my $nd (@nodelist) {
chomp $nd;
my $Nodeip = xCAT::NetworkUtils->getipaddr($nd);
# need node gateway
my $gateway = $nethash{$nd}{'gateway'};
# This should configure the iscsi disc on the client
my $tcmd = qq~/usr/lpp/bos.sysmgt/nim/methods/c_disc_target -a operation=discover -a target="$dump_target" -a dump_port="$dump_port" -a ipaddr="$SNip" -a lun_id="$dump_lunid"~;
my $hd = xCAT::InstUtils->xcmd($callback, $sub_req, "xdsh", $nd, $tcmd, 0);
if ($::RUNCMD_RC != 0)
{
my $rsp;
push @{$rsp->{data}}, "Could not run \'$tcmd\' on node $nd.\
n";
xCAT::MsgUtils->message("E", $rsp, $callback);
$error++;
next;
}
chomp $hd;
my $hdisk;
foreach my $line ( split(/\n/, $hd )) {
if ( $line =~ /hdisk/ ) {
$hdisk = $line;
if ($line =~ /:/) {
my $node;
($node, $hdisk) = split(': ', $line);
}
}
}
chomp $hdisk;
$hdisk =~ s/\s*//g;
if (!$hdisk) {
my $rsp;
push @{$rsp->{data}}, "Could not determine dump device for node $nd.\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
$error++;
next;
}
# define the disk on the client
my $mkcmd = qq~/usr/sbin/mkdev -l $hdisk~;
my $output = xCAT::InstUtils->xcmd($callback, $sub_req, "xdsh", $nd, $mkcmd, 0);
if ($::RUNCMD_RC != 0)
{
my $rsp;
push @{$rsp->{data}}, "Could not run \'$mkcmd\' on node $nd.\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
$error++;
next;
}
# configure the dump device, select either selective or full
# for the configdump attribute.
my $ccmd = qq~/usr/lpp/bos.sysmgt/nim/methods/c_config_dump -a configdump=$configdump -a target=$dump_target -a dump_port=$dump_port -a ipaddr=$SNip -a lun_id=$dump_lunid~;
$output = xCAT::InstUtils->xcmd($callback, $sub_req, "xdsh",
$nd, $ccmd, 0);
if ($::RUNCMD_RC != 0)
{
my $rsp;
push @{$rsp->{data}}, "Could not run \'$ccmd\' on node $nd.\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
$error++;
next;
}
# set the dump disk:
my $syscmd = qq~/usr/bin/sysdumpdev -p /dev/$hdisk~;
$output = xCAT::InstUtils->xcmd($callback, $sub_req, "xdsh", $nd, $syscmd, 0);
if ($::RUNCMD_RC != 0)
{
my $rsp;
push @{$rsp->{data}}, "Could not run \'$syscmd\' on node $nd.\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
$error++;
next;
}
my $rsp;
push @{$rsp->{data}}, "Set the primary dump device for node \'$nd\' to \'/dev/$hdisk\' and changed the dump target to \'$sn\'.\n";
xCAT::MsgUtils->message("I", $rsp, $callback);
}
}
}
if ($error) {
return 1;
}
return 0;
}
#----------------------------------------------------------------------------
=head3 getnimattr
Get the specified nim attrs form the named server
Returns:
undef - error
hash ref -
=cut
#-----------------------------------------------------------------------------
sub getnimattr
{
my $resname = shift;
my $attr = shift;
my $callback = shift;
my $target = shift;
my $sub_req = shift;
my @attrs = @$attr;
my %attrval;
if (!$resname) {
return undef;
}
if (!$target)
{
$target = xCAT::InstUtils->getnimprime();
}
chomp $target;
my $ncmd = "/usr/sbin/lsnim ";
foreach my $a (@attrs)
{
$ncmd .= "-a $a ";
}
$ncmd .= "$resname 2>/dev/null";
my $attrlist = xCAT::InstUtils->xcmd($callback, $sub_req, "xdsh", $target, $ncmd, 0);
if ($::RUNCMD_RC != 0)
{
if ($::VERBOSE) {
my $rsp;
push @{$rsp->{data}}, "Could not run lsnim command: \'$ncmd\'.\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
}
return undef;
}
foreach my $line (split(/\n/, $attrlist) ){
# look for attr name
foreach my $a (@attrs) {
chomp $a;
if ($line =~ /$a/) {
my ($stuff, $value) = split('=', $line);
chomp $value;
my ($val, $rest) = split(' ', $value);
# add to hash
$attrval{$a} = $val;
}
}
}
return \%attrval;
}
#----------------------------------------------------------------------------
=head3 sfsSLconfig
Does statelite setup when using a shared file system
The snmove cmd changes the xcatmaster value for the nodes
This means, that since we won't be running mkdsklsnode again,
we need to take care of the ststelite file changes here
- update statelite tables in DB
- run dolitesetup to re-create the statelite files stored
in the shared_root directories
- copy the new statelite files to the shared_root directory
on the target service node (only one since this is a
shared filesystem
- note: not copying the persistent directory on the MN
Arguments:
Returns:
0 - OK
1 - error
Usage: $ret = &sfsSLconfig(\@nodelist, \%nhash, \%sn_hash, $nimprime,
$callback, $sub_req);
=cut
#-----------------------------------------------------------------------------
sub sfsSLconfig
{
my $nodelist = shift;
my $nh = shift;
my $n_h = shift;
my $old_node_hash = shift;
my $nimprime = shift;
my $callback = shift;
my $sub_req = shift;
my @nodes = @$nodelist;
my %nhash = %{$nh};
my %sn_hash = %{$n_h};
my %imghash; # osimage def
my $statemnt;
my $server;
my $dir;
my $item = 0;
my %SLmodhash; # changes for the statelite DB table
# gather some basic info
my $targetsn; # name of SN to copy files to
my %objtype; # need to pass to getobjdefs
my %osinodes; # list of nodes for each osimage
my @osimage; # list of osimages
foreach my $n (@nodes) {
if (!grep(/$nhash{$n}{'provmethod'}/, @osimage) ){
push (@osimage, $nhash{$n}{'provmethod'});
$objtype{$nhash{$n}{'provmethod'}} = 'osimage';
push (@{$osinodes{$nhash{$n}{'provmethod'}}}, $n);
my ($sn, $snbak) = split(/,/, $sn_hash{$n}{servicenode});
if (!$targetsn) {
if (!xCAT::InstUtils->is_me($sn) ) {
$targetsn=$sn;
}
}
}
}
my $statetab = xCAT::Table->new('statelite', -create => 1);
my $recs = $statetab->getAllEntries;
#
# update the statelite DB tables
#
foreach my $line (@$recs)
{
$statemnt = $line->{statemnt};
# if the statemnt is a variable then skip it
if (grep /^\$/, $statemnt) {
next;
}
($server, $dir) = split(/:/, $statemnt);
chomp $server;
# see what nodes this entry applies to
my @nodeattr = &noderange($line->{node}, 0);
foreach my $n (@nodes)
{
# if the node is not in the noderange for this
# entry then skip it
if (!grep(/$n/, @nodeattr))
{
next;
}
# if the $server value was the old SN hostname
# then we need to
# update the statelite table with the new SN name
if ( $server eq $old_node_hash->{$n}->{'oldmaster'} ) {
my $stmnt = "$sn_hash{$n}{'xcatmaster'}:$dir";
$SLmodhash{$item}{'statemnt'} = $stmnt;
$SLmodhash{$item}{'node'} = $n;
$statetab->setAttribs({'node' => $n}, {'statemnt' => $stmnt, 'mntopts' => $line->{mntopts}, 'comments' => $line->{comments}, 'disable' => $line->{disable}});
}
}
} # end statelite DB update
# done with statelite table
$statetab->close();
# get the osimage defs
my %imghash = xCAT::DBobjUtils->getobjdefs(\%objtype, $callback);
if (!(%imghash))
{
my $rsp;
push @{$rsp->{data}}, "Could not get xCAT osimage definitions.\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 1;
}
#
# call dolitesetup() for each osimage needed for the nodes
# to re-do the statelite tables etc. in the shared_root dir
#
foreach my $i (@osimage)
{
# dolitesetup to update the shared_root table files
# - updates files in the sopot and shared_root resour
my $rc=xCAT::InstUtils->dolitesetup($i, \%imghash, \@{$osinodes{$i}}, $callback, $sub_req);
if ($rc eq 1) { # error
my $rsp;
push @{$rsp->{data}}, "Could not complete the statelite setup.\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 1;
}
} # end statelite setup
#
# copy files to target SN
#
foreach my $i (@osimage)
{
my $SRname = $imghash{$i}{shared_root};
if ($SRname) {
my $srloc = xCAT::InstUtils->get_nim_attr_val( $imghash{$i}{shared_root}, "location", $callback, $nimprime, $sub_req);
if ($srloc) {
my $cpcmd = qq~$::XCATROOT/bin/xdcp $targetsn ~;
my $output;
if (-f "$srloc/statelite.table") {
$cpcmd .= qq~$srloc/statelite.table ~;
}
if (-f "$srloc/litefile.table") {
$cpcmd .= qq~$srloc/litefile.table ~;
}
if (-f "$srloc/litetree.table") {
$cpcmd .= qq~$srloc/litetree.table ~;
}
if (-f "$srloc/aixlitesetup") {
$cpcmd .= qq~$srloc/aixlitesetup ~;
}
$cpcmd .= qq~$srloc/ ~;
$output=xCAT::InstUtils->xcmd($callback, $sub_req, "xdsh", $nimprime, $cpcmd, 0);
if ($::RUNCMD_RC != 0)
{
my $rsp;
push @{$rsp->{data}}, "Could not copy new statelite file to $targetsn\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
}
my $ddir = "$srloc/.default";
if (-d $ddir ) {
$cpcmd = qq~$::XCATROOT/bin/xdcp $targetsn -R $srloc/.default $srloc/~;
}
$output=xCAT::InstUtils->xcmd($callback, $sub_req, "xdsh", $nimprime, $cpcmd, 0);
if ($::RUNCMD_RC != 0)
{
my $rsp;
push @{$rsp->{data}}, "Could not copy new statelite information to $targetsn\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
}
}
}
} # end copy files
return 0;
}