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:
parent
6ca241c9d0
commit
e8df039d42
@ -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 can’t 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 can’t 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 customer’s 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 customer’s 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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;
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user