mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-10-31 19:32:31 +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:
		| @@ -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) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user