2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2025-05-29 09:13:08 +00:00

Make getadapter work during discovery process

This patch redesign the original getadapter plugins. Currently,
getadapter do not work as a common command but only a chain command
works during discovery.
This commit is contained in:
chenglch 2017-07-19 15:01:37 +08:00
parent 6ca241c9d0
commit e8df039d42
8 changed files with 81 additions and 892 deletions

View File

@ -1,51 +1,42 @@
Predict network adapter name before deployment
Predict network adapter name during discovery
==============================================
Traditionally, network interfaces in Linux are enumerated as eth[0123…], but
these names do not correspond to actual labels on the chassis. Now, most of
the linux distribution support naming the adapter with slot information which
makes adapter name predictable. xCAT add ``getadapter`` script which can be
running during discovery stage to detect the adapter names and pci slot
information to help customer configure the network.
Traditionally, network interfaces in Linux are enumerated as eth[0123…], but these names do not necessarily correspond to actual labels on the chassis. customer need a methods to get consistent and predictable network device name before provision or network configuration. xCAT provide a tool ``getadapter`` to help customer to resolve this problem.
**[Note]** : This feature needs to restart your target sever which you want to obtain network adapter from.
How to use get adapters
How to use getadapter
-----------------------
Set the chian table to run ``getadapter`` script ::
Using below command to obtain the network adapters information ::
getadapter <noderange>
chdef <noderange> chain="runcmd=getadapter"
Then will get output like below ::
When the discovery completed, the column ``nicsadapter`` of ```nics`` table is
updated.
View result with ``lsdef`` command ::
The whole scan result:
--------------------------------------
[node2] scan successfully, below are the latest data
node2:[1]->eno1!mac=34:40:b5:be:6a:80|pci=/pci0000:00/0000:00:01.0/0000:0c:00.0|candidatename=eno1/enp12s0f0/enx3440b5be6a80
node2:[2]->enp0s29u1u1u5!mac=36:40:b5:bf:44:33|pci=/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.1/2-1.1.5/2-1.1.5:1.0|candidatename=enp0s29u1u1u5/enx3640b5bf4433
--------------------------------------
[node1] scan successfully, below are the latest data
node1:[1]->eno1!mac=34:40:b5:be:6a:80|pci=/pci0000:00/0000:00:01.0/0000:0c:00.0|candidatename=eno1/enp12s0f0/enx3440b5be6a80
node1:[2]->enp0s29u1u1u5!mac=36:40:b5:bf:44:33|pci=/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.1/2-1.1.5/2-1.1.5:1.0|candidatename=enp0s29u1u1u5/enx3640b5bf4433
# lsdef <node>
.......
nicsadapter.enP3p3s0f0=mac=98:be:94:59:fa:cc linkstate=DOWN pci=/pci0003:00/0003:00:00.0/0003:01:00.0/0003:02:01.0/0003:03:00.0 candidatename=enP3p3s0f0/enx98be9459facc
nicsadapter.enP3p3s0f1=mac=98:be:94:59:fa:cd linkstate=DOWN pci=/pci0003:00/0003:00:00.0/0003:01:00.0/0003:02:01.0/0003:03:00.1 candidatename=enP3p3s0f1/enx98be9459facd
nicsadapter.enP3p3s0f2=mac=98:be:94:59:fa:ce linkstate=DOWN pci=/pci0003:00/0003:00:00.0/0003:01:00.0/0003:02:01.0/0003:03:00.2 candidatename=enP3p3s0f2/enx98be9459face
nicsadapter.enP3p3s0f3=mac=98:be:94:59:fa:cf linkstate=UP pci=/pci0003:00/0003:00:00.0/0003:01:00.0/0003:02:01.0/0003:03:00.3 candidatename=enP3p3s0f3/enx98be9459facf
.......
Below are the information ``getadapter`` trying to inspect:
Every node gets a separate section to display its all network adapters information, every network adapter owns single line which start as node name and followed by index and other information.
* **name**: the real adapter name used by genesis operation system
xCAT try its best to collect more information for each network adapter, but cant guarantee collect same much information for every one. If a network adapter can be derived by xcat genesis, this adapter will have a predictable name, if it cant be, it only has the information xcat can obtain.
below are the possible information:
* **name**: the consistent name which can be used by confignic directly in operating system which follow the same naming scheme with rhels7
* **pci**: the pci location
* **pci**: the pci slot location
* **mac**: the MAC address
* **candidatename**: All the names which satisfy predictable network device naming scheme, if customer needs to customize their network adapter name, they can choose one of them. (``confignic`` needs to do more work to support this. if customer want to use their own name, xcat should offer a interface to get customers input and change this column)
* **candidatename**: All the names which satisfy predictable network device naming scheme, if customer needs to customize their network adapter name, they can choose one of them. (``confignetwork`` needs to do more work to support this. if customer want to use their own name, xcat should offer a interface to get customers input and change this column)
* **vendor**: the vender of network device
* **modle**: the modle of network device
* **linkstate**: The link state of network device
* **linkstate**: The link state of network device

View File

@ -1,147 +0,0 @@
############
getadapter.1
############
.. highlight:: perl
****
NAME
****
\ **getadapter**\ - Obtain all network adapters's predictable name and some other information before provision or network configuration.
********
SYNOPSIS
********
\ **getadapter**\ \ *noderange*\ [\ **-f**\ ]
\ **getadapter**\ [\ **-h | -**\ **-help | -v | -**\ **-version | -V**\ ]
***********
DESCRIPTION
***********
Traditionally, network interfaces in Linux are enumerated as eth[0123...], but these names do not necessarily correspond to actual labels on the chassis. \ **getadapter**\ help customer to get predictable network device name and some other network adapter information before provision or network configuration.
\ **Since getadpter uses genesis to collect network adapters information, the target node will be restarted.**\
\ **getadapter**\ For each node within the <noderange>, follows below scheme:
If the target node is scanned for the first time, \ **getadapter**\ will trigger genesis to collect information then save the information at the \ **nicsadapter**\ column of nics table.
If the target node has ever been scanned, \ **getadapter**\ will use the information from nics table first.
If user hopes to scan the adapter information for the node but these information already exist, \ **-f**\ option can be used to start rescan process.
\ **getadapter**\ tries to collect more information for the target network device, but doesn't guarantee collect same much information for every network device.
******************************
\ **Collected information:**\
******************************
\ **name**\ : the consistent name which can be used by confignic directly in operating system which follow the same naming scheme with rhels7
\ **pci**\ : the pci location
\ **mac**\ : the MAC address
\ **candidatename**\ : All the names which satisfy predictable network device naming scheme. \ *(if xcat enhance confignic command later, user can use these names to configure their network adapter, even customize their name)*\
\ **vender**\ : the vender of network device
\ **model**\ : the model of network device
\ **linkstate**\ : the link state of network device
*******
OPTIONS
*******
\ **-h**\
Display usage message.
\ **-v**\
Command Version.
\ **-V**\
Display verbose message.
\ **-f**\
Force to trigger new round scan. ignore the data collected before.
********
EXAMPLES
********
1. To collect node[1-3]'s network device information, enter:
.. code-block:: perl
getadapter node[1-2]
Output is similar to:
.. code-block:: perl
-->Starting scan for: node1,node2
The whole scan result:
--------------------------------------
[node1]: Adapter information exists, no need to scan.
--------------------------------------
[node2] scan successfully, below are the latest data
node2:[1]->eno1!mac=34:40:b5:be:6a:80|pci=/pci0000:00/0000:00:01.0/0000:0c:00.0|candidatename=eno1/enp12s0f0/enx3440b5be6a80
node2:[2]->enp0s29u1u1u5!mac=36:40:b5:bf:44:33|pci=/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.1/2-1.1.5/2-1.1.5:1.0|candidatename=enp0s29u1u1u5/enx3640b5bf4433
Every node gets a separate section to display its all network adapters information, every network adapter owns single line which start as node name and followed by index and other information.
2. Force to trigger new round scan
.. code-block:: perl
getadatper node -f
********
SEE ALSO
********
noderange(3)|noderange.3

View File

@ -37,7 +37,6 @@ opt/xcat/bin/xcatclient opt/xcat/bin/lstree
opt/xcat/bin/xcatclient opt/xcat/bin/lsflexnode
opt/xcat/bin/xcatclient opt/xcat/bin/rmflexnode
opt/xcat/bin/xcatclient opt/xcat/bin/mkflexnode
opt/xcat/bin/xcatclient opt/xcat/bin/getadapter
opt/xcat/bin/xcatclientnnr opt/xcat/bin/lsslp
opt/xcat/bin/xcatclient opt/xcat/bin/imgcapture
opt/xcat/bin/xcatclientnnr opt/xcat/bin/swapnodes

View File

@ -1,94 +0,0 @@
=head1 NAME
B<getadapter> - Obtain all network adapters's predictable name and some other information before provision or network configuration.
=head1 SYNOPSIS
B<getadapter> I<noderange> [B<-f>]
B<getadapter> [B<-h>|B<--help>|B<-v>|B<--version>|B<-V>]
=head1 DESCRIPTION
Traditionally, network interfaces in Linux are enumerated as eth[0123...], but these names do not necessarily correspond to actual labels on the chassis. B<getadapter> help customer to get predictable network device name and some other network adapter information before provision or network configuration.
B<Since getadpter uses genesis to collect network adapters information, the target node will be restarted.>
B<getadapter> For each node within the <noderange>, follows below scheme:
If the target node is scanned for the first time, B<getadapter> will trigger genesis to collect information then save the information at the B<nicsadapter> column of nics table.
If the target node has ever been scanned, B<getadapter> will use the information from nics table first.
If user hopes to scan the adapter information for the node but these information already exist, B<-f> option can be used to start rescan process.
B<getadapter> tries to collect more information for the target network device, but doesn't guarantee collect same much information for every network device.
=head1 B<Collected information:>
=over 2
=item B<name>: the consistent name which can be used by confignic directly in operating system which follow the same naming scheme with rhels7
=item B<pci>: the pci location
=item B<mac>: the MAC address
=item B<candidatename>: All the names which satisfy predictable network device naming scheme. I<(if xcat enhance confignic command later, user can use these names to configure their network adapter, even customize their name)>
=item B<vender>: the vender of network device
=item B<model>: the model of network device
=item B<linkstate>: the link state of network device
=back
=head1 OPTIONS
B<-h>
Display usage message.
B<-v>
Command Version.
B<-V>
Display verbose message.
B<-f>
Force to trigger new round scan. ignore the data collected before.
=head1 EXAMPLES
1. To collect node[1-3]'s network device information, enter:
getadapter node[1-2]
Output is similar to:
-->Starting scan for: node1,node2
The whole scan result:
--------------------------------------
[node1]: Adapter information exists, no need to scan.
--------------------------------------
[node2] scan successfully, below are the latest data
node2:[1]->eno1!mac=34:40:b5:be:6a:80|pci=/pci0000:00/0000:00:01.0/0000:0c:00.0|candidatename=eno1/enp12s0f0/enx3440b5be6a80
node2:[2]->enp0s29u1u1u5!mac=36:40:b5:bf:44:33|pci=/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.1/2-1.1.5/2-1.1.5:1.0|candidatename=enp0s29u1u1u5/enx3640b5bf4433
Every node gets a separate section to display its all network adapters information, every network adapter owns single line which start as node name and followed by index and other information.
2. Force to trigger new round scan
getadatper node -f
=head1 SEE ALSO
L<noderange(3)|noderange.3>

View File

@ -163,7 +163,6 @@ ln -sf ../bin/xcatclient $RPM_BUILD_ROOT/%{prefix}/bin/lstree
ln -sf ../bin/xcatclient $RPM_BUILD_ROOT/%{prefix}/bin/lsflexnode
ln -sf ../bin/xcatclient $RPM_BUILD_ROOT/%{prefix}/bin/rmflexnode
ln -sf ../bin/xcatclient $RPM_BUILD_ROOT/%{prefix}/bin/mkflexnode
ln -sf ../bin/xcatclient $RPM_BUILD_ROOT/%{prefix}/bin/getadapter
ln -sf ../bin/xcatclientnnr $RPM_BUILD_ROOT/%{prefix}/bin/lsslp
ln -sf ../bin/xcatclientnnr $RPM_BUILD_ROOT/%{prefix}/bin/switchdiscover
ln -sf ../bin/xcatclientnnr $RPM_BUILD_ROOT/%{prefix}/bin/bmcdiscover

View File

@ -4,7 +4,6 @@
XCATPORT=3001
export XCATPORT
#XCATMASTER="10.3.5.21"
ADAPTERFILE="/tmp/adapterinfo"
SCANNICLOG="/tmp/adapterscan.log"
@ -17,8 +16,6 @@ fi
echo "<xcatrequest>
<command>getadapter</command>
<clienttype>cli</clienttype>
<noderange>$HOSTNAME</noderange>
<action>update</action>" >> "$ADAPTERFILE"
#scan adapters have recognized by operating system
@ -111,5 +108,4 @@ else
openssl s_client -connect $dhcps:$XCATPORT <"$ADAPTERFILE" >>"$SCANNICLOG" 2>&1
fi
fi
fi
fi

View File

@ -2,7 +2,7 @@
#-------------------------------------------------------
=head1
xCAT plugin package to handle getadapter management
xCAT plugin package to handle getadapter request from genesis.
Supported command:
getadapter->getadapter
@ -18,37 +18,9 @@ BEGIN {
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;
#-------------------------------------------------------
@ -67,50 +39,16 @@ sub handled_commands
};
}
#-------------------------------------------------------
=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.
This subroutine is used for the command called from genesis. As the client of
genesis is not a command line interface, this hook comand can help save one
fork compare with a common command.
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.
return REQUEST_UPDATE if request is received.
return REQUEST_ERROR if error happens.
Usage example:
This is a hook function in xcatd, do not use it directly.
@ -118,565 +56,70 @@ sub process_request
#-----------------------------------------------------------------
sub route_request {
my ($request, $callback, $subreq) = @_;
my $request = shift;
my $command = $request->{command}->[0];
my $ret = xCAT::State->REQUEST_ERROR;
if (!$request->{node}) {
return xCAT::State->REQUEST_WAIT;
if ($command eq "getadapter") {
if (!defined($request->{'action'}) || $request->{action}->[0] ne xCAT::State->UPDATE_ACTION) {
return xCAT::State->REQUEST_ERROR;
}
my $node = $request->{'_xcat_clienthost'}->[0];
if (!$request->{nic}) {
xCAT::MsgUtils->message("S", "$node: Could not get any nic information");
return xCAT::State->REQUEST_ERROR;
}
my $nics = \@{ $request->{nic} };
xCAT::MsgUtils->message("S", "$node: callback message from getadapter received");
if (update_nics_info($node, $nics)!=0) {
return xCAT::State->REQUEST_ERROR;
}
}
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;
return xCAT::State->REQUEST_UPDATE;
}
#-------------------------------------------------------
=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 => ['rinstall'],
node => ["$node"],
arg => ['runcmd=getadapter'],
},
$subreq, 0, 1);
if ($::RUNCMD_RC != 0) {
foreach my $out (@$outref) {
$callback->({data => "$out"})
}
$callback->({ error => "failed to run command: rinstall $node runcmd=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;
}
my @nic_attrs = ();
my @output_attrs = ();
if (exists($msg->{nic}->[$i]->{mac})) {
push(@output_attrs, "mac=" . $msg->{nic}->[$i]->{mac});
if ($interface_exists) {
push(@nic_attrs, "mac=" . $msg->{nic}->[$i]->{mac});
}
}
if (exists($msg->{nic}->[$i]->{pcilocation})) {
push(@output_attrs, "pci=" . $msg->{nic}->[$i]->{pcilocation});
if ($interface_exists) {
push(@nic_attrs, "pci=" . $msg->{nic}->[$i]->{pcilocation});
}
}
if (exists($msg->{nic}->[$i]->{predictablename})) {
push(@output_attrs, "candidatename=" . $msg->{nic}->[$i]->{predictablename});
}
if (exists($msg->{nic}->[$i]->{vendor})) {
$msg->{nic}->[$i]->{vendor} =~ s/^\s+|\s+$//g;
push(@output_attrs, "vendor=" . $msg->{nic}->[$i]->{vendor});
}
if (exists($msg->{nic}->[$i]->{model})) {
$msg->{nic}->[$i]->{model} =~ s/^\s+|\s+$//g;
push(@output_attrs, "model=" . $msg->{nic}->[$i]->{model});
}
if (exists($msg->{nic}->[$i]->{linkstate})) {
push(@output_attrs, "linkstate=" . (split(' ', $msg->{nic}->[$i]->{linkstate}))[0]);
if ($interface_exists) {
push(@nic_attrs, "linkstate=". (split(' ', $msg->{nic}->[$i]->{linkstate}))[0]);
}
}
if (@nic_attrs) {
$data .= join(" ", @nic_attrs);
}
$output .= join("|", @output_attrs);
$output .= "\n";
}
$callback->({ data => "$output" });
if (!$has_nic) {
$callback->({ data => "$node: nics table will not be updated as not any ".
"useful information could be found with udevadm command." });
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;
}
sub update_nics_info {
my $node = shift;
my $nics_ptr = shift;
my (@nics, @data, %updates);
@nics = @{$nics_ptr};
my $update_nics_table_func = sub {
my $node = shift;
my $nics = shift;
my $nics_table = xCAT::Table->new('nics');
unless ($nics_table) {
xCAT::MsgUtils->message("S", "Unable to open nics table, denying");
xCAT::MsgUtils->message("S", "Unable to open nics table for getadapter, denying");
return -1;
}
my $taskstate_table = xCAT::Table->new('taskstate');
unless ($taskstate_table) {
xCAT::MsgUtils->message("S", "Unable to open taskstate table, denying");
$updates{'nicsadapter'} = $nics;
if ($nics_table->setAttribs({ 'node' => $node }, \%updates) != 0) {
xCAT::MsgUtils->message("S", "Error to update nics table for getadapter.");
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;
for (my $i = 0; $i < scalar(@nics); $i++) {
if ($nics[$i]->{interface}) {
my @nic_attrs = ();
if ($nics[$i]->{mac}) {
push(@nic_attrs, "mac=".$nics[$i]->{mac}->[0]);
}
if ($nics[$i]->{linkstate}) {
push (@nic_attrs, "linkstate=". (split(' ', $nics[$i]->{linkstate}->[0]))[0]);
}
if($nics[$i]->{pcilocation}) {
push(@nic_attrs, "pci=" . $nics[$i]->{pcilocation}->[0]);
}
if ($nics[$i]->{predictablename}) {
push(@nic_attrs, "candidatename=" . $nics[$i]->{predictablename}->[0]);
}
if (@nic_attrs) {
push(@data, $nics[$i]->{interface}->[0]."!".join(" ", @nic_attrs));
}
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);
return $update_nics_table_func->($node, join(",", @data));
}
1;

View File

@ -1383,6 +1383,8 @@ sub initDB
"$::XCATROOT/sbin/chtab priority=2.3 policy.commands=lsxcatd policy.rule=allow;";
$chtabcmds .=
"$::XCATROOT/sbin/chtab priority=2.1 policy.commands=remoteimmsetup policy.rule=allow;";
$chtabcmds .=
"$::XCATROOT/sbin/chtab priority=4.9 policy.commands=getadapter policy.rule=allow;";
my $outref = xCAT::Utils->runcmd("$chtabcmds", 0);
if ($::RUNCMD_RC != 0)