mirror of
https://github.com/xcat2/xcat-core.git
synced 2025-05-22 11:42:05 +00:00
1. Add allow policy for getadapter 2. enhance the error message for different mgt when running getadapter partial-issue: #1174
724 lines
22 KiB
Perl
724 lines
22 KiB
Perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
|
|
#-------------------------------------------------------
|
|
|
|
=head1
|
|
xCAT plugin package to handle getadapter management
|
|
|
|
Supported command:
|
|
getadapter->getadapter
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
package xCAT_plugin::getadapter;
|
|
|
|
BEGIN {
|
|
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : -d '/opt/xcat' ? '/opt/xcat' : '/usr';
|
|
}
|
|
use lib "$::XCATROOT/lib/perl";
|
|
|
|
use xCAT::Table;
|
|
use xCAT::Utils;
|
|
use xCAT::FifoPipe;
|
|
use xCAT::MsgUtils;
|
|
use xCAT::State;
|
|
use Data::Dumper;
|
|
use Getopt::Long;
|
|
use File::Path;
|
|
use Term::ANSIColor;
|
|
use Time::Local;
|
|
use strict;
|
|
use Class::Struct;
|
|
use XML::Simple;
|
|
use Storable qw(dclone);
|
|
|
|
my %usage = (
|
|
"getadapter" => "Usage:\n\tgetadapter [-h|--help|-v|--version|V]\n\tgetadapter <noderange> [-f]",
|
|
);
|
|
|
|
my $VERBOSE = 0;
|
|
use constant OPT_FORCE => 0;
|
|
use constant OPT_UPDATE => 1;
|
|
|
|
use constant GET_ADPATER_DIR => "/var/run/getadapter";
|
|
use constant ALARM_TIMEOUT => 1800;
|
|
|
|
unless (-d GET_ADPATER_DIR) {
|
|
mkpath(GET_ADPATER_DIR);
|
|
}
|
|
|
|
my %child_pids;
|
|
my $timeout_event = 0;
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 handled_commands
|
|
|
|
Return list of commands handled by this plugin
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
|
|
sub handled_commands
|
|
{
|
|
return {
|
|
getadapter => "getadapter",
|
|
};
|
|
}
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 process_request
|
|
|
|
Process the command.
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
sub process_request
|
|
{
|
|
my $request = shift;
|
|
my $callback = shift;
|
|
my $subreq = shift;
|
|
my $command = $request->{command}->[0];
|
|
|
|
$SIG{INT} = $SIG{TERM} = sub {
|
|
xCAT::MsgUtils->message("W", "getadapter: int or term signal received, clean up task state");
|
|
exit(clean_up());
|
|
};
|
|
|
|
if ($command eq "getadapter") {
|
|
&handle_getadapter($request, $callback, $subreq);
|
|
}
|
|
return;
|
|
}
|
|
|
|
#------------------------------------------------------------------
|
|
|
|
=head3 route_request
|
|
|
|
Route the request, this funciton is called in the reqeust process.
|
|
|
|
return REQUEST_UPDATE if update request arrived. Now just send
|
|
message to the waiting process with fifo pipe.
|
|
|
|
(TODO) If getadapter is used in chain table to complete
|
|
the discovery process, the adapter information can be
|
|
updated directly in immediate plugin and there is no need
|
|
to fork plugin process.
|
|
|
|
return REQUEST_WAIT if inspect request arrived. Tell xcatd fork
|
|
plugin process to handle this request.
|
|
return REQUEST_ERROR if error happened.
|
|
|
|
Usage example:
|
|
This is a hook function in xcatd, do not use it directly.
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------
|
|
sub route_request {
|
|
my ($request, $callback, $subreq) = @_;
|
|
my $command = $request->{command}->[0];
|
|
my $ret = xCAT::State->REQUEST_ERROR;
|
|
|
|
if (scalar(@{ $request->{node} }) == 0) {
|
|
return $ret;
|
|
}
|
|
|
|
my $build_request_message_func = sub {
|
|
my $req = shift;
|
|
my $xs = new XML::Simple();
|
|
my $nic_info;
|
|
$nic_info->{'nic'} = $req->{'nic'};
|
|
$nic_info->{'node'} = $req->{node}->[0];
|
|
return $xs->XMLout($nic_info);
|
|
};
|
|
|
|
if (defined($request->{'action'}) and $request->{action}->[0] eq xCAT::State->UPDATE_ACTION) {
|
|
|
|
# may be a callback request, just check the state then send message
|
|
# no need to fork a plugin process.
|
|
my $node = ${ $request->{'node'} }[0];
|
|
my $taskstate_table = xCAT::Table->new('taskstate');
|
|
unless ($taskstate_table) {
|
|
xCAT::MsgUtils->message("S", "Unable to open taskstate table, denying");
|
|
return $ret;
|
|
}
|
|
my $node_obj = $taskstate_table->getAttribs({ 'node' => $node, 'command' => $command }, 'state', 'pid');
|
|
|
|
if (defined($node_obj) and $node_obj->{'state'} eq xCAT::State->WAIT_STATE) {
|
|
my $msg_queue = xCAT::FifoPipe->send_message(
|
|
xCAT::Utils->full_path($node_obj->{'pid'}, GET_ADPATER_DIR),
|
|
&$build_request_message_func($request));
|
|
$ret = xCAT::State->REQUEST_UPDATE;
|
|
}
|
|
else {
|
|
xCAT::MsgUtils->message("S", "Error to find the node in waiting state");
|
|
}
|
|
$taskstate_table->close();
|
|
} elsif (!defined($request->{'action'}) or $request->{action}->[0] eq xCAT::State->INSPECT_ACTION) {
|
|
|
|
# new request, fork a plugin child process to handle this request.
|
|
$ret = xCAT::State->REQUEST_WAIT;
|
|
}
|
|
return $ret;
|
|
}
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 handle_getadapter
|
|
|
|
This function check the command option, then call the
|
|
function to complete the request.
|
|
|
|
Usage example:
|
|
This function is called from process_request,
|
|
do not call it directly.
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
|
|
sub handle_getadapter {
|
|
my $request = shift;
|
|
my $callback = shift;
|
|
my $subreq = shift;
|
|
my $command = $request->{command}->[0];
|
|
my @opts;
|
|
|
|
my @args = ();
|
|
my $HELP;
|
|
my $VERSION;
|
|
my $FORCE;
|
|
my $UPDATE;
|
|
if (ref($request->{arg})) {
|
|
@args = @{ $request->{arg} };
|
|
} else {
|
|
@args = ($request->{arg});
|
|
}
|
|
@ARGV = @args;
|
|
Getopt::Long::Configure("bundling");
|
|
Getopt::Long::Configure("no_pass_through");
|
|
if (!GetOptions("h|help" => \$HELP,
|
|
"v|version" => \$VERSION,
|
|
"f" => \$FORCE,
|
|
"u" => \$UPDATE,
|
|
"V" => \$VERBOSE
|
|
)) {
|
|
if ($usage{$command}) {
|
|
my $rsp = {};
|
|
$rsp->{error}->[0] = $usage{$command};
|
|
$rsp->{errorcode}->[0] = 1;
|
|
$callback->($rsp);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if ($HELP) {
|
|
if ($usage{$command}) {
|
|
my %rsp;
|
|
$rsp{data}->[0] = $usage{$command};
|
|
$callback->(\%rsp);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if ($VERSION) {
|
|
my $ver = xCAT::Utils->Version();
|
|
my %rsp;
|
|
$rsp{data}->[0] = "$ver";
|
|
$callback->(\%rsp);
|
|
return;
|
|
}
|
|
@opts = ($FORCE, $UPDATE);
|
|
|
|
if (!defined($request->{'action'}) or $request->{action}->[0] eq xCAT::State->INSPECT_ACTION) {
|
|
return inspect_adapter($request, $callback, $subreq, \@opts);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
#------------------------------------------------------------------
|
|
|
|
=head3 clean_up
|
|
|
|
Clean up the getadapter running environment
|
|
|
|
return 1 if clean up failed
|
|
|
|
Usage example:
|
|
clean_up()
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------
|
|
sub clean_up {
|
|
my $ret = 0;
|
|
foreach (keys %child_pids) {
|
|
kill 2, $_;
|
|
}
|
|
xCAT::MsgUtils->message("S", "Getadapter: clean up task state in database");
|
|
|
|
# NOTE(chenglch): Currently xcatd listener process has bug in signal handler,
|
|
# just comment out these code.
|
|
my $taskstate_table = xCAT::Table->new('taskstate');
|
|
|
|
if ($taskstate_table) {
|
|
$taskstate_table->delEntries({ 'pid' => getppid() });
|
|
$taskstate_table->close();
|
|
}
|
|
else {
|
|
xCAT::MsgUtils->message("S", "Clean up taskstate error");
|
|
$ret = 1;
|
|
}
|
|
xCAT::FifoPipe->remove_pipe(xCAT::Utils->full_path(getppid(), GET_ADPATER_DIR));
|
|
return $ret;
|
|
}
|
|
|
|
|
|
#------------------------------------------------------------------
|
|
|
|
=head3 deploy_genesis
|
|
|
|
Fork processes to boot the target node into genesis
|
|
|
|
return array of nodes which are booting geneses.
|
|
|
|
Usage example:
|
|
my @nodes= ('node1', 'node2', 'node3');
|
|
my $nodes_desc_ptr, a hash pointer to the description of nodes array.
|
|
@nodes = deploy_genesis(\@nodes, $nodes_desc_ptr, $callback, $subreq);
|
|
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------
|
|
sub deploy_genesis {
|
|
my $nodes_ptr = shift;
|
|
my $nodes_desc_ptr = shift;
|
|
my $callback = shift;
|
|
my $subreq = shift;
|
|
my @nodes = @{$nodes_ptr};
|
|
my $pid;
|
|
|
|
my $child_process_func = sub {
|
|
my ($node, $node_desc_ptr, $callback, $subreq) = @_;
|
|
my $outref = xCAT::Utils->runxcmd(
|
|
{
|
|
command => ['nodeset'],
|
|
node => ["$node"],
|
|
arg => ['runcmd=getadapter'],
|
|
},
|
|
$subreq, 0, 1);
|
|
if ($::RUNCMD_RC != 0) {
|
|
$callback->({ error => "failed to run command: nodeset $node runcmd=getadapter", errorcode => 1 });
|
|
return 1;
|
|
}
|
|
# TODO: use rinstall to replace the following code when rinstall is ready.
|
|
if ($node_desc_ptr->{mgt} eq "ipmi") {
|
|
$outref = xCAT::Utils->runxcmd(
|
|
{
|
|
command => ["rsetboot"],
|
|
node => ["$node"],
|
|
arg => ['net'],
|
|
},
|
|
$subreq, 0, 1);
|
|
if ($::RUNCMD_RC != 0) {
|
|
$callback->({ error => "failed to run command: rsetboot $node net", errorcode => 1 });
|
|
return 1;
|
|
}
|
|
$outref = xCAT::Utils->runxcmd(
|
|
{
|
|
command => ['rpower'],
|
|
node => ["$node"],
|
|
arg => ['reset'],
|
|
},
|
|
$subreq, 0, 1);
|
|
if ($::RUNCMD_RC != 0) {
|
|
$callback->({ error => "failed to run command: rpower $node reset", errorcode => 1 });
|
|
return 1;
|
|
}
|
|
} elsif ($node_desc_ptr->{mgt} eq "kvm") {
|
|
$outref = xCAT::Utils->runxcmd(
|
|
{
|
|
command => ['rpower'],
|
|
node => ["$node"],
|
|
arg => ['reset'],
|
|
},
|
|
$subreq, 0, 1);
|
|
if ($::RUNCMD_RC != 0) {
|
|
$callback->({ error => "failed to run command: rpower $node reset", errorcode => 1 });
|
|
return 1;
|
|
}
|
|
} elsif ($node_desc_ptr->{mgt} eq "hmc") {
|
|
$outref = xCAT::Utils->runxcmd(
|
|
{
|
|
command => ["rnetboot"],
|
|
node => ["$node"],
|
|
},
|
|
$subreq, 0, 1);
|
|
if ($::RUNCMD_RC != 0) {
|
|
$callback->({ error => "failed to run command: rnetboot $node", errorcode => 1 });
|
|
return 1;
|
|
}
|
|
} else {
|
|
$callback->({ error => "$node: The mgt configuration is not supported by getadapter.",
|
|
errorcode => 1 });
|
|
return 1;
|
|
}
|
|
$callback->({data=>"$node: Booting into genesis, this could take several minutes..."});
|
|
return 0;
|
|
}; # end of child_process_func
|
|
|
|
$SIG{CHLD} = 'DEFAULT';
|
|
foreach my $node (@nodes) {
|
|
$pid = xCAT::Utils->xfork();
|
|
if (!defined($pid)) {
|
|
$callback->({ error => "failed to fork process to restart $node", errorcode => 1 });
|
|
$node = undef;
|
|
last;
|
|
} elsif ($pid == 0) {
|
|
|
|
# child process
|
|
$SIG{INT} = $SIG{TERM} = 'DEFAULT';
|
|
my $node_desc_ptr = $nodes_desc_ptr->{$node};
|
|
xCAT::MsgUtils->trace($VERBOSE, "d", "getadapter: fork new process $$ to start scaning $node");
|
|
my $ret = &$child_process_func($node, $node_desc_ptr, $callback, $subreq);
|
|
exit($ret);
|
|
} else {
|
|
|
|
# Parent process
|
|
$child_pids{$pid} = $node;
|
|
}
|
|
}
|
|
|
|
# Wait for all processes to end
|
|
my $cpid = 0;
|
|
while (keys %child_pids) {
|
|
if (($cpid = wait()) > 0) {
|
|
my $status = $?;
|
|
if ($status != 0) {
|
|
my $node = $child_pids{$cpid};
|
|
|
|
#delete nodes if child process error.
|
|
map { $_ = undef if $_ eq $node } @nodes;
|
|
}
|
|
delete $child_pids{$cpid};
|
|
}
|
|
}
|
|
|
|
# delete undef
|
|
@nodes = grep /./, @nodes;
|
|
return @nodes;
|
|
}
|
|
|
|
#------------------------------------------------------------------
|
|
|
|
=head3 update_adapter_result
|
|
|
|
Update the adapter information in the nics table.
|
|
Print the adapter information to STDOUT.
|
|
|
|
Input:
|
|
$msg: A hash pointer parsed from message from fifopipe
|
|
$nodes_desc_ptr: Nodes description pointer
|
|
$opts_ptr: A pointer to the nodes option
|
|
$callback: callback object
|
|
|
|
return -1 if unexpectd error.
|
|
return 0 success
|
|
|
|
Usage example:
|
|
my $msg;
|
|
my $nodes_desc_ptr;
|
|
my $opts_ptr;
|
|
my $callback
|
|
update_adapter_result($msg, $nodes_desc_ptr, $opts_ptr, $callback));
|
|
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------
|
|
sub update_adapter_result {
|
|
my $msg = shift;
|
|
my $nodes_desc_ptr = shift;
|
|
my $opts_ptr = shift;
|
|
my $callback = shift;
|
|
my $node = $msg->{'node'};
|
|
my $nicnum = scalar @{ $msg->{nic} };
|
|
my ($output, $data, $interface_exists, $has_nic, %updates);
|
|
|
|
$data = "";
|
|
$output = "[$node] scan successfully below is result:\n";
|
|
for (my $i = 0 ; $i < $nicnum ; $i++) {
|
|
$output.= "$node:[$i]->";
|
|
$interface_exists = 0;
|
|
|
|
if (exists($msg->{nic}->[$i]->{interface})) {
|
|
$output .= $msg->{nic}->[$i]->{interface};
|
|
if ($has_nic) {
|
|
$data .= "," . $msg->{nic}->[$i]->{interface} . "!";
|
|
}
|
|
else {
|
|
$data .= $msg->{nic}->[$i]->{interface} . "!";
|
|
}
|
|
$interface_exists = 1;
|
|
$has_nic = 1;
|
|
}
|
|
if (exists($msg->{nic}->[$i]->{mac})) {
|
|
$output .= "!mac=" . $msg->{nic}->[$i]->{mac};
|
|
if ($interface_exists) {
|
|
$data .= " mac=" . $msg->{nic}->[$i]->{mac};
|
|
}
|
|
}
|
|
if (exists($msg->{nic}->[$i]->{pcilocation})) {
|
|
$output .= "|pci=" . $msg->{nic}->[$i]->{pcilocation};
|
|
if ($interface_exists) {
|
|
$data .= "pci=" . $msg->{nic}->[$i]->{pcilocation};
|
|
}
|
|
}
|
|
if (exists($msg->{nic}->[$i]->{predictablename})) {
|
|
$output .= "|candidatename=" . $msg->{nic}->[$i]->{predictablename};
|
|
}
|
|
if (exists($msg->{nic}->[$i]->{vendor})) {
|
|
$output .= "|vendor=" . $msg->{nic}->[$i]->{vendor};
|
|
}
|
|
if (exists($msg->{nic}->[$i]->{model})) {
|
|
$output .= "|model=" . $msg->{nic}->[$i]->{model};
|
|
}
|
|
if (exists($msg->{nic}->[$i]->{linkstate})) {
|
|
$output .= "|linkstate=" . $msg->{nic}->[$i]->{linkstate};
|
|
if ($interface_exists) {
|
|
$data .= " linkstate=" . $msg->{nic}->[$i]->{linkstate};
|
|
}
|
|
}
|
|
$output .= "\n";
|
|
}
|
|
$callback->({ data => "$output" });
|
|
if (!$has_nic) {
|
|
$callback->({ data => "$node: Couldn't find interface name information detected by udevadm,"
|
|
." the nics table will not be updated." });
|
|
return 0;
|
|
}
|
|
my $nics_table = xCAT::Table->new('nics');
|
|
unless ($nics_table) {
|
|
xCAT::MsgUtils->message("S", "Unable to open nics table, denying");
|
|
$callback->({ error => "Error to connect to nics table.",
|
|
errorcode => 1 });
|
|
return -1;
|
|
}
|
|
$updates{'nicsadapter'} = $data;
|
|
if ($nics_table->setAttribs({ 'node' => $node }, \%updates) != 0) {
|
|
xCAT::MsgUtils->message("S", "Error to update nics table.");
|
|
$callback->({ error => "Error to update nics table.",
|
|
errorcode => 1 });
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#------------------------------------------------------------------
|
|
|
|
=head3 do_inspect
|
|
|
|
The main function to run the getadapter process
|
|
|
|
|
|
Input:
|
|
$nodesptr: The nodes pointer
|
|
$nodes_desc_ptr: Nodes description pointer
|
|
$opts_ptr: Option pointer
|
|
$callback: callback object
|
|
$subreq: xcat sub request
|
|
|
|
return -1 if unexpectd error.
|
|
return 0 success
|
|
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------
|
|
|
|
sub do_inspect {
|
|
my $nodesptr = shift;
|
|
my $nodes_desc_ptr = shift;
|
|
my $opts_ptr = shift;
|
|
my $callback = shift;
|
|
my $subreq = shift;
|
|
my @nodes = @{$nodesptr};
|
|
my $updates;
|
|
my $msg; # parse from xml
|
|
|
|
my $parse_request_message_func = sub {
|
|
my $xml = shift;
|
|
my $xs = new XML::Simple();
|
|
return $xs->XMLin($xml);
|
|
};
|
|
|
|
my $timeout_output_func = sub {
|
|
my $nodes_ptr = shift;
|
|
my $callback = shift;
|
|
foreach my $node (@{$nodes_ptr}) {
|
|
if ($node) {
|
|
$callback->({ error => "$node: Timeout to get the adapter information",
|
|
errorcode => 1 });
|
|
}
|
|
}
|
|
};
|
|
|
|
my $taskstate_table = xCAT::Table->new('taskstate');
|
|
unless ($taskstate_table) {
|
|
xCAT::MsgUtils->message("S", "Unable to open taskstate table, denying");
|
|
$callback->({ error => "Error to connect to taskstate table.",
|
|
errorcode => 1 });
|
|
return -1;
|
|
}
|
|
|
|
# TODO(chenglch) Currently xcat db access is a single process model, this is
|
|
# safe. In the future:
|
|
# 1. If database is refactored, we need to protect the task
|
|
# state with Optimistic Lock of database.
|
|
# 2. If we leverage the memcache or other cache database, we can make use of
|
|
# the feature of the CAS to provide the atomic operation.
|
|
foreach my $node (@nodes) {
|
|
$updates->{$node}->{'command'} = "getadapter";
|
|
$updates->{$node}->{'state'} = xCAT::State->WAIT_STATE;
|
|
$updates->{$node}->{'pid'} = getppid();
|
|
}
|
|
$taskstate_table->setNodesAttribs($updates);
|
|
$taskstate_table->close();
|
|
@nodes = deploy_genesis(\@nodes, $nodes_desc_ptr, $callback, $subreq);
|
|
my $total = scalar(@nodes);
|
|
my $count = 0;
|
|
my @node_buf;
|
|
|
|
$SIG{ALRM} = sub {
|
|
xCAT::MsgUtils->message("W", "getadapter: alarm signal received");
|
|
$timeout_event = 1;
|
|
|
|
# pipe broken, wake up the wait fifo pipe
|
|
xCAT::FifoPipe->remove_pipe(xCAT::Utils->full_path(getppid(), GET_ADPATER_DIR));
|
|
};
|
|
alarm(ALARM_TIMEOUT);
|
|
|
|
while ($count < $total) {
|
|
my $c = xCAT::FifoPipe->recv_message(
|
|
xCAT::Utils->full_path(getppid(), GET_ADPATER_DIR),
|
|
\@node_buf);
|
|
if ($c <= 0) {
|
|
if ($timeout_event == 1) {
|
|
&$timeout_output_func(\@nodes, $callback);
|
|
clean_up();
|
|
return -1;
|
|
}
|
|
xCAT::MsgUtils->message("S", "Unexpected pipe error, abort.");
|
|
return -1;
|
|
}
|
|
|
|
my $nics_table = xCAT::Table->new('nics');
|
|
unless ($nics_table) {
|
|
xCAT::MsgUtils->message("S", "Unable to open nics table, denying");
|
|
return -1;
|
|
}
|
|
|
|
my $taskstate_table = xCAT::Table->new('taskstate');
|
|
unless ($taskstate_table) {
|
|
xCAT::MsgUtils->message("S", "Unable to open taskstate table, denying");
|
|
return -1;
|
|
}
|
|
|
|
for (my $i = 0 ; $i < $c ; $i++) {
|
|
$msg = &$parse_request_message_func($node_buf[$i]);
|
|
|
|
# delete the node
|
|
map { $_ = undef if $_ eq $msg->{'node'} } @nodes;
|
|
if (update_adapter_result($msg, $nodes_desc_ptr, $opts_ptr, $callback)) {
|
|
return -1;
|
|
}
|
|
$taskstate_table->delEntries({ 'node' => $msg->{'node'} });
|
|
}
|
|
$count += $c;
|
|
$taskstate_table->close();
|
|
$nics_table->close();
|
|
}
|
|
xCAT::MsgUtils->trace($VERBOSE, "d", "getadapter: remove pipe " . xCAT::Utils->full_path(getppid(), GET_ADPATER_DIR));
|
|
xCAT::FifoPipe->remove_pipe(xCAT::Utils->full_path(getppid(), GET_ADPATER_DIR));
|
|
return 0;
|
|
}
|
|
|
|
#------------------------------------------------------------------
|
|
|
|
=head3 inspect_adapter
|
|
|
|
Process the getadapter command option.
|
|
|
|
return -1 if unexpectd error.
|
|
return 0 success.
|
|
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------
|
|
sub inspect_adapter {
|
|
my $request = shift;
|
|
my $callback = shift;
|
|
my $subreq = shift;
|
|
my $opts_ptr = shift;
|
|
my @nodes;
|
|
my @entries;
|
|
my %nodes_desc;
|
|
|
|
my $init_desc_func = sub {
|
|
my $nodes_ptr = shift;
|
|
my $callback = shift;
|
|
my $nodes_desc_ptr = shift;
|
|
my @nodes = @{$nodes_ptr};
|
|
my $nodehm_table = xCAT::Table->new('nodehm');
|
|
unless ($nodehm_table) {
|
|
xCAT::MsgUtils->message("S", "Unable to open nodehm table, denying");
|
|
return -1;
|
|
}
|
|
my $entries = $nodehm_table->getNodesAttribs($nodes_ptr, ['mgt']);
|
|
unless ($entries) {
|
|
xCAT::MsgUtils->message("S", "No records about " . join(",", @nodes) . " in nodehm table");
|
|
return -1;
|
|
}
|
|
$nodehm_table->close();
|
|
foreach my $node (@nodes) {
|
|
if(!defined($entries->{$node}) || !defined($entries->{$node}->[0]->{mgt})) {
|
|
$callback->({ error => "$node: mgt configuration can not be found.",
|
|
errorcode => 1 });
|
|
next;
|
|
}
|
|
$nodes_desc_ptr->{$node}->{'mgt'} = $entries->{$node}->[0]->{mgt};
|
|
}
|
|
return 0;
|
|
}; # end of init_desc_func
|
|
|
|
# Get the nodes should be inspect.
|
|
if ($opts_ptr->[OPT_FORCE]) {
|
|
@nodes = @{ $request->{node} };
|
|
} else {
|
|
my $nics_table = xCAT::Table->new('nics');
|
|
unless ($nics_table) {
|
|
xCAT::MsgUtils->message("S", "Unable to open nics table, denying");
|
|
return -1;
|
|
}
|
|
my $entries = $nics_table->getNodesAttribs($request->{node}, ['nicsadapter']);
|
|
foreach my $node (@{ $request->{node} }) {
|
|
if($entries->{$node} && $entries->{$node}->[0]->{nicsadapter}) {
|
|
$callback->({ data => "$node: Adapter information exists, no need to inspect." });
|
|
next;
|
|
}
|
|
push(@nodes, $node);
|
|
}
|
|
}
|
|
if (scalar(@nodes) == 0) {
|
|
$callback->({ data => "No adapter information need to inspect." });
|
|
return -1;
|
|
}
|
|
xCAT::MsgUtils->trace($VERBOSE, "d", "getadapter: scaning start for " . join(",", @nodes));
|
|
if (&$init_desc_func(\@nodes, $callback, \%nodes_desc)) {
|
|
return -1;
|
|
}
|
|
return do_inspect(\@nodes, \%nodes_desc, $opts_ptr, $callback, $subreq);
|
|
}
|
|
|
|
1;
|