2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2025-07-28 15:21:11 +00:00

Fork a rflash process for each node

Original implementation use thread to deal with the rflash
procedure for multiple nodes, but thread is not suggested
by perl. This patch aims to replace the thread with process.
This commit is contained in:
chenglch
2015-11-11 02:19:15 -05:00
parent e9b165b2f2
commit a52c7166c2

View File

@@ -36,6 +36,7 @@ my $iem_support;
my $vpdhash;
my %allerrornodes=();
my $global_sessdata;
my %child_pids;
my $IPMIXCAT = "/opt/xcat/bin/ipmitool-xcat";
my $NON_BLOCK = 1;
@@ -1574,12 +1575,12 @@ sub calc_ipmitool_version {
# 0 when no response from bmc
#----------------------------------------------------------------#
sub check_bmc_status_with_ipmitool {
my $pre_cmd = shift;
my $interval = shift;
my $retry = shift;
my $count = 0;
my $cmd = $pre_cmd." power status";
while ($count < $retry) {
my $pre_cmd = shift;
my $interval = shift;
my $retry = shift;
my $count = 0;
my $cmd = $pre_cmd." power status";
while ($count < $retry) {
xCAT::Utils->runcmd($cmd, -1);
if ($::RUNCMD_RC != 0) {
sleep($interval);
@@ -1640,7 +1641,6 @@ sub do_firmware_update {
$callback,$sessdata->{node},%allerrornodes);
return -1;
}
# step 2 reset cold
$cmd = $pre_cmd." mc reset cold";
$output = xCAT::Utils->runcmd($cmd, -1);
@@ -1694,14 +1694,22 @@ sub rflash {
if ($sessdata->{subcommand} eq 'check') {
my %firmware_version;
check_firmware_version($sessdata, \%firmware_version);
foreach my $c_id (@{$sessdata->{component_ids}}) {
my $msg="";
my $i;
for ($i = 0; $i < scalar(@{$sessdata->{component_ids}}); $i++) {
my $c_id = ${$sessdata->{component_ids}}[$i];
my $version = $firmware_version{$c_id};
my $format_ver = sprintf("%3d.%02x %02X%02X%02X%02X", $version->[0], $version->[1], $version->[2],
my $format_ver = sprintf("%3d.%02x %02X%02X%02X%02X",
$version->[0], $version->[1], $version->[2],
$version->[3], $version->[4], $version->[5]);
xCAT::SvrUtils::sendmsg("Node firmware version for component $c_id: $format_ver",
$callback,$sessdata->{node},%allerrornodes);
$msg = $msg.$sessdata->{node}.": ".
"Node firmware version for component $c_id: $format_ver";
if ( $i != scalar(@{$sessdata->{component_ids}}) -1 ) {
$msg = $msg."\n";
}
}
$callback->({data=>$msg});
return;
}
return do_firmware_update($sessdata);
@@ -1718,20 +1726,74 @@ sub rflash {
}
}
sub start_rflash_thread {
#----------------------------------------------------------------#
# Running rflash procedure in a child process
# Note (chenglch) If the parent process abort unexpectedly, the
# child process can not be terminated by xcat.
#----------------------------------------------------------------#
sub do_rflash_process {
my $node = shift;
# NOTE (chenglch): Actually if multiple client or rest api works on the same node,
# the bmc of the node may not be protected while rflash is running. As xcat may not
# support lock on node level, just require a lock for rflash command for specific node.
my $lock = xCAT::Utils->acquire_lock("rflash_$node", $NON_BLOCK);
if (! $lock){
xCAT::SvrUtils::sendmsg ([1,"rflash is running on $node, please retry after a while"],
my $pid = xCAT::Utils->xfork;
if ( !defined($pid) ) {
xCAT::SvrUtils::sendmsg ([1,"Fork rflash process Error."],
$callback,$node,%allerrornodes);
return;
}
donode($node, @_);
while (xCAT::IPMI->waitforrsp()) { yield };
xCAT::Utils->release_lock($lock, $NON_BLOCK);
# child
elsif ( $pid == 0 ) {
$SIG{CHLD} = $SIG{INT} = $SIG{TERM} = "DEFAULT";
# NOTE (chenglch): Actually if multiple client or rest api works on the same node,
# the bmc of the node may not be protected while rflash is running. As xcat may not
# support lock on node level, just require a lock for rflash command for specific node.
my $lock = xCAT::Utils->acquire_lock("rflash_$node", $NON_BLOCK);
if (! $lock){
xCAT::SvrUtils::sendmsg ([1,"rflash is running on $node, please retry after a while"],
$callback,$node,%allerrornodes);
exit(1);
}
donode($node, @_);
while (xCAT::IPMI->waitforrsp()) { yield };
xCAT::Utils->release_lock($lock, $NON_BLOCK);
exit(0);
}
# parent
else {
$child_pids{$pid} = $node;
}
return $pid;
}
sub start_rflash_processes {
my $donargs_ptr = shift;
my @donargs = @{$donargs_ptr};
my $ipmitimeout = shift;
my $ipmitrys = shift;
my $command = shift;
my %namedargs=@_;
my $extra=$namedargs{-args};
my @exargs=@$extra;
$SIG{INT} = $SIG{TERM} = sub {
foreach ( keys %child_pids ) {
kill 2, $_;
}
exit 0;
};
$SIG{CHLD} = sub {
my $cpid;
while ( ( $cpid = waitpid( -1, WNOHANG ) ) > 0 ) {
if ( $child_pids{$cpid} ) {
delete $child_pids{$cpid};
}
}
};
foreach (@donargs) {
do_rflash_process( $_->[0],$_->[1],$_->[2],$_->[3],$_->[4],
$ipmitimeout,$ipmitrys,$command,-args=>\@exargs);
}
while ( ( scalar( keys %child_pids ) ) > 0 ) {
yield;
}
}
sub fpc_firmup_config {
@@ -7544,6 +7606,8 @@ sub process_request {
if ($request->{command}->[0] eq "rflash") {
my %args_hash;
if (!defined($extrargs)) {
$callback->({error=>"No option or hpm file is provided.",
errorcode=>1});
return;
}
foreach my $opt (@$extrargs) {
@@ -7634,21 +7698,10 @@ sub process_request {
}
}
my $children = 0;
my $sub_fds = new IO::Select;
# NOTE (chenglch) rflash for one node need about 5-10 minutes. There is no need to rflash node
# one by one, so parallel thread is used here.
# one by one, fork a process for each node.
if ($command eq 'rflash') {
my %thread_group;
# TODO (chenglch) the size of the noderange maybe very large, so many thread is created here.
# Thread pool or limit size is needed.
foreach (@donargs) {
$thread_group{$_->[0]} = threads->new(\&start_rflash_thread, $_->[0],$_->[1],$_->[2],$_->[3],$_->[4],
$ipmitimeout,$ipmitrys,$command,-args=>\@exargs);
}
foreach (@donargs) {
$thread_group{$_->[0]}->join();
}
start_rflash_processes(\@donargs, $ipmitimeout,$ipmitrys,$command,-args=>\@exargs);
}
else {
foreach (@donargs) {
@@ -7664,34 +7717,6 @@ sub process_request {
}
}
while (xCAT::IPMI->waitforrsp()) { yield };
if (keys %needbladeinv) {
#ok, we have some inventory data that, for now, suggests blade plugin to getdata from blade plugin
# my @bladenodes = keys %needbladeinv;
# $request->{arg}=['mac'];
# $request->{node}=\@bladenodes;
# require xCAT_plugin::blade;
# xCAT_plugin::blade::process_request($request,$callback);
}
####return;
####while ($sub_fds->count > 0 and $children > 0) {
#### my $handlednodes={};
#### forward_data($callback,$sub_fds,$handlednodes);
#### #update the node status to the nodelist.status table
#### if ($check) {
#### updateNodeStatus($handlednodes, \@allerrornodes);
#### }
####}
####
#####Make sure they get drained, this probably is overkill but shouldn't hurt
####my $rc=1;
####while ( $rc>0 ) {
#### my $handlednodes={};
#### $rc=forward_data($callback,$sub_fds,$handlednodes);
#### #update the node status to the nodelist.status table
#### if ($check) {
#### updateNodeStatus($handlednodes, \@allerrornodes);
#### }
####}
if ($check) {
#print "allerrornodes=@allerrornodes\n";