mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-10-31 03:12:30 +00:00 
			
		
		
		
	Merge pull request #3456 from robin2008/nodeset-disjoint
Fix #3088, Using 'disjointdhcps' site attribute to make nodeset request will only be handled on service node for nodes it manages
This commit is contained in:
		| @@ -110,8 +110,9 @@ site Attributes: | ||||
|    dhcplease:  The lease time for the dhcp client. The default value is 43200. | ||||
|    | ||||
|    disjointdhcps:  If set to '1', the .leases file on a service node only contains | ||||
|                    the nodes it manages. The default value is '0'. | ||||
|                    '0' value means include all the nodes in the subnet. | ||||
|                    the nodes it manages. And when 'sharedtftp' is disabled, nodeset handles | ||||
|                    boot loader configuration on a service node only for the nodes it manages. | ||||
|                    The default value is '0'. It means include all the nodes in the subnet. | ||||
|    | ||||
|    pruneservices:  Whether to enable service pruning when noderm is run (i.e. | ||||
|                    removing DHCP entries when noderm is executed) | ||||
|   | ||||
| @@ -19,7 +19,7 @@ Name | ||||
| **************** | ||||
|  | ||||
|  | ||||
| \ **nodeset**\  \ *noderange*\  [\ **boot**\  | \ **stat**\  | \ **offline**\  | \ **runcmd=bmcsetup**\  | \ **osimage**\ [=\ *imagename*\ ] | \ **shell**\  | \ **shutdown**\ ] | ||||
| \ **nodeset**\  \ *noderange*\  [\ **boot**\  | \ **stat**\  [\ **-a**\ ]| \ **offline**\  | \ **runcmd=bmcsetup**\  | \ **osimage**\ [=\ *imagename*\ ] | \ **shell**\  | \ **shutdown**\ ] | ||||
|  | ||||
| \ **nodeset**\  \ *noderange*\  \ **osimage**\ [=\ *imagename*\ ] [\ **-**\ **-noupdateinitrd**\ ] [\ **-**\ **-ignorekernelchk**\ ] | ||||
|  | ||||
| @@ -101,7 +101,7 @@ A user can supply their own scripts to be run on the mn or on the service node ( | ||||
|  | ||||
| \ **stat**\  | ||||
|   | ||||
|  Display the current boot loader config file description for the nodes requested | ||||
|  Display the current boot loader config file description for the nodes requested. When \ **disjointdhcps**\  is set, using \ **-a**\  to display them on all available service nodes. | ||||
|   | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -1645,10 +1645,14 @@ sub getNodeIPaddress | ||||
| { | ||||
|     require xCAT::Table; | ||||
|     my $nodetocheck = shift; | ||||
|     my $port        = shift; | ||||
|     my $nodeip; | ||||
|     if ($nodetocheck eq 'xCAT::NetworkUtils') {    #was called with -> syntax | ||||
|         $nodetocheck = shift; | ||||
|     } | ||||
|  | ||||
|     $nodeip = xCAT::NetworkUtils->getipaddr($nodetocheck); | ||||
|     # Quick return if pass in an IP | ||||
|     return $nodetocheck if (xCAT::NetworkUtils->isIpaddr($nodetocheck)); | ||||
|  | ||||
|     my $nodeip = xCAT::NetworkUtils->getipaddr($nodetocheck); | ||||
|     if (!$nodeip) | ||||
|     { | ||||
|         my $hoststab = xCAT::Table->new('hosts'); | ||||
| @@ -1666,6 +1670,51 @@ sub getNodeIPaddress | ||||
| } | ||||
|  | ||||
|  | ||||
| #------------------------------------------------------------------------------- | ||||
|  | ||||
| =head3   checkNodeIPaddress | ||||
|     Arguments: | ||||
|        Node name  only one at a time  | ||||
|     Returns: a hash object contains IP or Error | ||||
|     Globals: | ||||
|         none | ||||
|     Example:   my $ipresult = xCAT::NetworkUtils::checkNodeIPaddress($nodetocheck); | ||||
|  | ||||
| =cut | ||||
|  | ||||
| #------------------------------------------------------------------------------- | ||||
|  | ||||
| sub checkNodeIPaddress | ||||
| { | ||||
|     require xCAT::Table; | ||||
|     my $nodetocheck = shift; | ||||
|     if ($nodetocheck eq 'xCAT::NetworkUtils') {    #was called with -> syntax | ||||
|         $nodetocheck = shift; | ||||
|     } | ||||
|     my $ret; | ||||
|  | ||||
|     my $nodeip; | ||||
|     my $hoststab = xCAT::Table->new('hosts'); | ||||
|     my $ent = $hoststab->getNodeAttribs($nodetocheck, ['ip']); | ||||
|     if ($ent->{'ip'}) { | ||||
|         $nodeip = $ent->{'ip'}; | ||||
|     } | ||||
|  | ||||
|     # Get the IP from DNS | ||||
|     my $dnsip = xCAT::NetworkUtils->getipaddr($nodetocheck); | ||||
|     if (!$dnsip) | ||||
|     { | ||||
|         $ret->{'error'} = "The $nodetocheck can not be resolved."; | ||||
|         $ret->{'ip'} = $nodeip if ($nodeip); | ||||
|     } elsif (!$nodeip) { | ||||
|         $ret->{'ip'} = $dnsip; | ||||
|     } else { | ||||
|         $ret->{'ip'} = $nodeip; | ||||
|         $ret->{'error'} = "Defined IP address of $nodetocheck is inconsistent with DNS." if ($nodeip ne $dnsip); | ||||
|     } | ||||
|     return $ret; | ||||
| } | ||||
|  | ||||
|  | ||||
| #------------------------------------------------------------------------------- | ||||
|  | ||||
|   | ||||
| @@ -1029,8 +1029,9 @@ passed as argument rather than by table value', | ||||
| " dhcpsetup:  If set to 'n', it will skip the dhcp setup process in the nodeset cmd.\n\n" . | ||||
| " dhcplease:  The lease time for the dhcp client. The default value is 43200.\n\n" . | ||||
| " disjointdhcps:  If set to '1', the .leases file on a service node only contains\n" . | ||||
| "                 the nodes it manages. The default value is '0'.\n" . | ||||
| "                 '0' value means include all the nodes in the subnet.\n\n" . | ||||
| "                 the nodes it manages. And when 'sharedtftp' is disabled, nodeset handles\n" . | ||||
| "                 boot loader configuration on a service node only for the nodes it manages.\n" . | ||||
| "                 The default value is '0'. It means include all the nodes in the subnet.\n\n" . | ||||
| " pruneservices:  Whether to enable service pruning when noderm is run (i.e.\n" . | ||||
| "                 removing DHCP entries when noderm is executed)\n\n" . | ||||
| " managedaddressmode: The mode of networking configuration during node provision.\n" . | ||||
|   | ||||
| @@ -2,6 +2,7 @@ package xCAT::Scope; | ||||
|  | ||||
| use xCAT::Utils; | ||||
| use xCAT::Table; | ||||
| use xCAT::TableUtils; | ||||
| use xCAT::ServiceNodeUtils qw(getSNList); | ||||
|  | ||||
|  | ||||
| @@ -125,16 +126,17 @@ sub get_parallel_scope { | ||||
| =head3 get_broadcast_scope_with_parallel | ||||
|  | ||||
|     Convert a request object to an array of multiple requests according to the  | ||||
|     splitted node range. | ||||
|     splitted node range. Also it replicates the requests to all required service | ||||
|     nodes or management node. | ||||
|  | ||||
|     Arguments: | ||||
|        Reference of request | ||||
|        Callback: TODO, Optional, the Callback will be used to filter the nodes | ||||
|        SN list: Array of target service nodes | ||||
|     Returns: An array of requests | ||||
|     Error: | ||||
|         none | ||||
|     Example: | ||||
|         my $reqs = xCAT::Scope->get_broadcast_scope($request); | ||||
|         my $reqs = xCAT::Scope->get_broadcast_scope_with_parallel($request, \@snlist); | ||||
| =cut | ||||
|  | ||||
| #----------------------------------------------------------------------------- | ||||
| @@ -145,25 +147,118 @@ sub get_broadcast_scope_with_parallel { | ||||
|     } | ||||
|     #Exit if the packet has been preprocessed in its history | ||||
|     if ($req->{_xcatpreprocessed}->[0] == 1) { return [$req]; } | ||||
|     $req->{_xcatpreprocessed}->[0] = 1; | ||||
|  | ||||
|     #Handle the one for current management/service node | ||||
|     my $reqs = get_parallel_scope($req);  | ||||
|     my @requests = @$reqs; | ||||
|     my $snlist = shift; | ||||
|  | ||||
|     #Broadcast the request to other management/service nodes | ||||
|     foreach (xCAT::ServiceNodeUtils->getSNList()) { | ||||
|         if (xCAT::NetworkUtils->thishostisnot($_)) { | ||||
|             my $xcatdest = $_; | ||||
|             my $reqcopy = {%$req}; | ||||
|             $reqcopy->{'_xcatdest'} = $_; | ||||
|             $reqcopy->{_xcatpreprocessed}->[0] = 1; | ||||
|             #Apply callback to filter the node range in future. | ||||
|             $reqs = get_parallel_scope($reqcopy); | ||||
|             foreach (@$reqs) { | ||||
|                 push @requests, {%$_}; | ||||
|             } | ||||
|     my $reqs = get_parallel_scope($req); | ||||
|  | ||||
|     my @requests = (); # The request array will be return. | ||||
|     push @requests, @$reqs; | ||||
|  | ||||
|     # when this method is called on service node, it is required to broadcast to MN too. | ||||
|     # get site.master from DB in order to dispatch to MN ( MN will not be added in servicenode table) | ||||
|     if ( xCAT::Utils->isServiceNode() ) { | ||||
|         my @entries = xCAT::TableUtils->get_site_attribute("master"); | ||||
|         my $master = $entries[0]; | ||||
|         foreach (@$reqs) { | ||||
|             my $reqcopy = {%$_}; | ||||
|             $reqcopy->{'_xcatdest'} = $master; | ||||
|             push @requests, $reqcopy; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #Broadcast the request to all service nodes | ||||
|     foreach (@$snlist) { | ||||
|         my $xcatdest = $_; | ||||
|         next unless (xCAT::NetworkUtils->thishostisnot($xcatdest)); | ||||
|  | ||||
|         foreach (@$reqs) { | ||||
|             my $reqcopy = {%$_}; | ||||
|             $reqcopy->{'_xcatdest'} = $xcatdest; | ||||
|             push @requests, $reqcopy; | ||||
|         } | ||||
|     } | ||||
|     return \@requests; | ||||
| } | ||||
|  | ||||
| #----------------------------------------------------------------------------- | ||||
|  | ||||
| =head3 get_broadcast_disjoint_scope_with_parallel | ||||
|  | ||||
|     Convert a request object to an array of multiple requests according to the  | ||||
|     splitted node range. Also it replicates the requests to all required service | ||||
|     nodes or management node, but the request to a service node will only contains  | ||||
|     the node range it manages. | ||||
|  | ||||
|     Arguments: | ||||
|        Reference of request | ||||
|        SN hash: Hash of target service nodes => Managed CNs | ||||
|        Special servers: Array of servers, those servers are required to handle whole noderange. | ||||
|     Returns: An array of requests | ||||
|     Error: | ||||
|         none | ||||
|     Example: | ||||
|         my $reqs = xCAT::Scope->get_broadcast_disjoint_scope_with_parallel($request, \@snhash); | ||||
| =cut | ||||
|  | ||||
| #----------------------------------------------------------------------------- | ||||
| sub get_broadcast_disjoint_scope_with_parallel { | ||||
|     my $req = shift; | ||||
|     if ($req =~ /xCAT::Scope/) { | ||||
|         $req = shift; | ||||
|     } | ||||
|     #Exit if the packet has been preprocessed in its history | ||||
|     if ($req->{_xcatpreprocessed}->[0] == 1) { return [$req]; } | ||||
|     $req->{_xcatpreprocessed}->[0] = 1; | ||||
|  | ||||
|     my $sn_hash = shift; | ||||
|     my $extras = shift; | ||||
|  | ||||
|     my @requests = (); # The request array will be return. | ||||
|     my $reqs = get_parallel_scope($req); | ||||
|  | ||||
|     my $handled4me = 0;  # indicate myself is already handled. | ||||
|     my %prehandledhash = ();# the servers which is already handled. | ||||
|     foreach (@$extras) { | ||||
|         my $xcatdest = $_; | ||||
|         if (xCAT::NetworkUtils->thishostisnot($xcatdest)) { | ||||
|             # TODO, To avoid sending request to a multi-home server many times. | ||||
|             foreach (@$reqs) { | ||||
|                 my $reqcopy = {%$_}; | ||||
|                 $reqcopy->{'_xcatdest'} = $xcatdest; | ||||
|                 push @requests, $reqcopy; | ||||
|             } | ||||
|             $prehandledhash{$xcatdest} = 1; | ||||
|         } elsif ($handled4me == 0) { | ||||
|             push @requests, @$reqs; | ||||
|             $handled4me = 1; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #Broadcast the request to all available service nodes | ||||
|     foreach (keys %$sn_hash) { | ||||
|         my $xcatdest = $_; | ||||
|         # to check if the SN already handled | ||||
|         next if (exists($prehandledhash{$xcatdest})); | ||||
|  | ||||
|         if (xCAT::NetworkUtils->thishostisnot($xcatdest)) { | ||||
|             my $reqcopy = {%$req}; | ||||
|             $reqcopy->{'_xcatdest'} = $xcatdest; | ||||
|             $reqcopy->{'node'} = $sn_hash->{$xcatdest}; | ||||
|  | ||||
|             $reqs = get_parallel_scope($reqcopy); | ||||
|             push @requests, @$reqs; | ||||
|         } elsif ($handled4me == 0) { | ||||
|             my $reqcopy = {%$req}; | ||||
|             $reqcopy->{'node'} = $sn_hash->{$xcatdest}; | ||||
|  | ||||
|             $reqs = get_parallel_scope($reqcopy); | ||||
|             push @requests, @$reqs; | ||||
|             $handled4me = 1; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return \@requests; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -484,7 +484,7 @@ Options: | ||||
|       "Usage: | ||||
|    Common: | ||||
|       nodeset [-h|--help|-v|--version] | ||||
|       nodeset <noderange> [shell|boot|runcmd=bmcsetup|osimage[=<imagename>]|offline|shutdown|stat]", | ||||
|       nodeset <noderange> [shell|boot|runcmd=bmcsetup|osimage[=<imagename>]|offline|shutdown|stat [-a]]", | ||||
|     "rmflexnode" => | ||||
|       "Usage: | ||||
|     rmflexnode [-h|--help|-v|--version] | ||||
|   | ||||
| @@ -4,7 +4,7 @@ B<nodeset> - set the boot state for a noderange | ||||
|  | ||||
| =head1 B<Synopsis> | ||||
|  | ||||
| B<nodeset> I<noderange> [B<boot> | B<stat> | B<offline> | B<runcmd=bmcsetup> | B<osimage>[=I<imagename>] | B<shell> | B<shutdown>] | ||||
| B<nodeset> I<noderange> [B<boot> | B<stat> [B<-a>]| B<offline> | B<runcmd=bmcsetup> | B<osimage>[=I<imagename>] | B<shell> | B<shutdown>] | ||||
|  | ||||
| B<nodeset> I<noderange> B<osimage>[=I<imagename>] [B<--noupdateinitrd>] [B<--ignorekernelchk>] | ||||
|  | ||||
| @@ -68,7 +68,7 @@ If you would like to run a task after deployment, you can define that task with | ||||
|  | ||||
| =item B<stat> | ||||
|  | ||||
| Display the current boot loader config file description for the nodes requested | ||||
| Display the current boot loader config file description for the nodes requested. When B<disjointdhcps> is set, using B<-a> to display them on all available service nodes. | ||||
|  | ||||
| =item B<runcmd=bmcsetup> | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| # IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html | ||||
| package xCAT_plugin::grub2; | ||||
| use Data::Dumper; | ||||
|  | ||||
| use Sys::Syslog; | ||||
| use xCAT::Scope; | ||||
| use xCAT::Utils; | ||||
| @@ -123,12 +123,10 @@ sub setstate { | ||||
|  | ||||
|                     # We are in the service node pools, print error if no facing ip. | ||||
|                     if (xCAT::InstUtils->is_me($sn)) { | ||||
|                         my @myself = xCAT::NetworkUtils->determinehostname(); | ||||
|                         my $myname = $myself[ (scalar @myself) - 1 ]; | ||||
|                         $::callback->( | ||||
|                             { | ||||
|                                 error => [ | ||||
|                                     "$myname: $ipfnd[1] on service node $sn" | ||||
|                                     "$::myxcatname: $ipfnd[1] on service node $sn" | ||||
|                                 ], | ||||
|                                 errorcode => [1] | ||||
|                             } | ||||
| @@ -140,7 +138,7 @@ sub setstate { | ||||
|                 $::callback->( | ||||
|                     { | ||||
|                         error => [ | ||||
|                             "$myname: $ipfnd[1]" | ||||
|                             "$::myxcatname: $ipfnd[1]" | ||||
|                         ], | ||||
|                         errorcode => [1] | ||||
|                     } | ||||
| @@ -176,9 +174,9 @@ sub setstate { | ||||
|         $kern->{kcmdline} .= " " . $cmdhashref->{volatile}; | ||||
|     } | ||||
|  | ||||
|     my $pcfg; | ||||
|     unless (-d "$tftpdir/boot/grub2") { | ||||
|         mkpath("$tftpdir/boot/grub2"); | ||||
|     my $bootloader_root = "$tftpdir/boot/grub2"; | ||||
|     unless (-d "$bootloader_root") { | ||||
|         mkpath("$bootloader_root"); | ||||
|     } | ||||
|     my $nodemac; | ||||
|     my %client_nethash = xCAT::DBobjUtils->getNetwkInfo([$node]); | ||||
| @@ -186,9 +184,10 @@ sub setstate { | ||||
|     my $cref = $chainhash{$node}->[0]; #$chaintab->getNodeAttribs($node,['currstate']); | ||||
|  | ||||
|     # remove the old boot configuration files and create a new one, but only if not offline directive | ||||
|     system("find $tftpdir/boot/grub2/ -inum \$(stat --printf \%i $tftpdir/boot/grub2/$node 2>/dev/null) -exec rm -f {} \\; 2>/dev/null"); | ||||
|     system("find $bootloader_root/ -inum \$(stat --printf \%i $bootloader_root/$node 2>/dev/null) -exec rm -f {} \\; 2>/dev/null"); | ||||
|     my $pcfg; | ||||
|     if ($cref and $cref->{currstate} ne "offline") { | ||||
|         open($pcfg, '>', $tftpdir . "/boot/grub2/" . $node); | ||||
|         open($pcfg, '>', "$bootloader_root/" . $node); | ||||
|         print $pcfg "#" . $cref->{currstate} . "\n"; | ||||
|  | ||||
|         if (($::XCATSITEVALS{xcatdebugmode} eq "1") or ($::XCATSITEVALS{xcatdebugmode} eq "2")) { | ||||
| @@ -294,11 +293,6 @@ sub setstate { | ||||
|             print $pcfg "}"; | ||||
|             close($pcfg); | ||||
|         } | ||||
|         my $inetn = xCAT::NetworkUtils->getipaddr($node); | ||||
|         unless ($inetn) { | ||||
|             syslog("local1|err", "xCAT unable to resolve IP for $node in grub2 plugin"); | ||||
|             return; | ||||
|         } | ||||
|     } else { | ||||
|         close($pcfg); | ||||
|     } | ||||
| @@ -334,9 +328,9 @@ sub setstate { | ||||
|         my $pname = "grub.cfg-" . sprintf("%02X%02X%02X%02X", @ipa); | ||||
|  | ||||
|         # remove the old boot configuration file and copy (link) a new one, but only if not offline directive | ||||
|         unlink($tftpdir . "/boot/grub2/" . $pname); | ||||
|         unlink("$bootloader_root/" . $pname); | ||||
|         if ($cref and $cref->{currstate} ne "offline") { | ||||
|             link($tftpdir . "/boot/grub2/" . $node, $tftpdir . "/boot/grub2/" . $pname); | ||||
|             link("$bootloader_root/" . $node, "$bootloader_root/" . $pname); | ||||
|         } | ||||
|     } | ||||
|      | ||||
| @@ -359,9 +353,9 @@ sub setstate { | ||||
|         my $pname = "grub.cfg-01-" . $tmp; | ||||
|  | ||||
|         # remove the old boot configuration file and copy (link) a new one, but only if not offline directive | ||||
|         unlink($tftpdir . "/boot/grub2/" . $pname); | ||||
|         unlink("$bootloader_root/" . $pname); | ||||
|         if ($cref and $cref->{currstate} ne "offline") { | ||||
|             link($tftpdir . "/boot/grub2/" . $node, $tftpdir . "/boot/grub2/" . $pname); | ||||
|             link("$bootloader_root/" . $node, "$bootloader_root/" . $pname); | ||||
|         } | ||||
|     } | ||||
|     return; | ||||
| @@ -402,12 +396,14 @@ sub preprocess_request { | ||||
|  | ||||
|     #use Getopt::Long; | ||||
|     my $HELP; | ||||
|     my $ALLFLAG; | ||||
|     my $VERSION; | ||||
|     my $VERBOSE; | ||||
|     Getopt::Long::Configure("bundling"); | ||||
|     Getopt::Long::Configure("pass_through"); | ||||
|     if (!GetOptions('h|?|help' => \$HELP, | ||||
|             'v|version' => \$VERSION, | ||||
|             'a'           =>\$ALLFLAG, | ||||
|             'V'         => \$VERBOSE    #>>>>>>>used for trace log>>>>>>> | ||||
|         )) { | ||||
|         if ($usage{$command}) { | ||||
| @@ -469,12 +465,12 @@ sub preprocess_request { | ||||
|         xCAT::ServiceNodeUtils->getSNandCPnodes(\@$nodes, \@SN, \@CN); | ||||
|         unless (($args[0] eq 'stat') or ($args[0] eq 'enact')) { | ||||
|             if ((@SN > 0) && (@CN > 0)) {    # there are both SN and CN | ||||
|                 my $rsp; | ||||
|                 $rsp->{data}->[0] = | ||||
|                 my %rsp; | ||||
|                 $rsp{errorcode}->[0] = 1; | ||||
|                 $rsp{error}->[0] = | ||||
| "Nodeset was run with a noderange containing both service nodes and compute nodes. This is not valid. You must submit with either compute nodes in the noderange or service nodes. \n"; | ||||
|                 xCAT::MsgUtils->message("E", $rsp, $callback1); | ||||
|                 $callback1->(\%rsp); | ||||
|                 return; | ||||
|  | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @@ -482,10 +478,40 @@ sub preprocess_request { | ||||
|         if ($req->{inittime}->[0]) { | ||||
|             return [$req]; | ||||
|         } | ||||
|         if (@CN > 0) {    # if compute nodes broadcast to all servicenodes | ||||
|             return xCAT::Scope->get_broadcast_scope_with_parallel($req); | ||||
|         if (@CN > 0) {    # if compute nodes only, then broadcast to servic enodes | ||||
|  | ||||
|             my @sn = xCAT::ServiceNodeUtils->getSNList(); | ||||
|             unless ( @sn > 0 ) { | ||||
|                 return xCAT::Scope->get_parallel_scope($req) | ||||
|             } | ||||
|  | ||||
|             my $mynodeonly  = 0; | ||||
|             my @entries = xCAT::TableUtils->get_site_attribute("disjointdhcps"); | ||||
|             my $t_entry = $entries[0]; | ||||
|             if (defined($t_entry)) { | ||||
|                 $mynodeonly = $t_entry; | ||||
|             } | ||||
|             $req->{'_disjointmode'} = [$mynodeonly]; | ||||
|             xCAT::MsgUtils->trace(0, "d", "grub2: disjointdhcps=$mynodeonly"); | ||||
|  | ||||
|             if ($mynodeonly == 0 || $ALLFLAG) { # broadcast to all service nodes | ||||
|                 return xCAT::Scope->get_broadcast_scope_with_parallel($req, \@sn); | ||||
|             } | ||||
|  | ||||
|             my $sn_hash = xCAT::ServiceNodeUtils->getSNformattedhash(\@CN, "xcat", "MN"); | ||||
|             my @dhcpsvrs = (); | ||||
|             my $ntab = xCAT::Table->new('networks'); | ||||
|             if ($ntab) { | ||||
|                 foreach (@{ $ntab->getAllEntries() }) { | ||||
|                     next unless ($_->{dynamicrange}); | ||||
|                     # if dynamicrange specified but dhcpserver was not - issue error message | ||||
|                     push @dhcpsvrs, $_->{dhcpserver} if ($_->{dhcpserver}) | ||||
|                 } | ||||
|             } | ||||
|             return xCAT::Scope->get_broadcast_disjoint_scope_with_parallel($req, $sn_hash, \@dhcpsvrs); | ||||
|         } | ||||
|     } | ||||
|     # Do not dispatch to service nodes if non-sharedtftp or the node range contains only SNs. | ||||
|     return xCAT::Scope->get_parallel_scope($req); | ||||
| } | ||||
|  | ||||
| @@ -496,19 +522,16 @@ sub process_request { | ||||
|     $sub_req    = shift; | ||||
|     my $command = $request->{command}->[0]; | ||||
|     %breaknetbootnodes = (); | ||||
|     %normalnodes       = (); | ||||
|     %normalnodes       = (); # It will be fill-up by method: setstate. | ||||
|  | ||||
|     my @args; | ||||
|     my @nodes; | ||||
|     my @rnodes; | ||||
|  | ||||
|     #>>>>>>>used for trace log start>>>>>>> | ||||
|     my %opt; | ||||
|     my $verbose_on_off = 0; | ||||
|     if (ref($::XNBA_request->{arg})) { | ||||
|         @args = @{ $::XNBA_request->{arg} }; | ||||
|     if (ref($request->{arg})) { | ||||
|         @args = @{ $request->{arg} }; | ||||
|     } else { | ||||
|         @args = ($::XNBA_request->{arg}); | ||||
|         @args = ($request->{arg}); | ||||
|     } | ||||
|     @ARGV = @args; | ||||
|     GetOptions('V' => \$opt{V}); | ||||
| @@ -516,6 +539,10 @@ sub process_request { | ||||
|  | ||||
|     #>>>>>>>used for trace log end>>>>>>> | ||||
|  | ||||
|     my @hostinfo = xCAT::NetworkUtils->determinehostname(); | ||||
|     $::myxcatname = $hostinfo[-1]; | ||||
|     xCAT::MsgUtils->trace($verbose_on_off, "d", "grub2: running on $::myxcatname"); | ||||
|     my @rnodes; | ||||
|     if (ref($request->{node})) { | ||||
|         @rnodes = @{ $request->{node} }; | ||||
|     } else { | ||||
| @@ -528,61 +555,101 @@ sub process_request { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     #if not shared tftpdir, then filter, otherwise, set up everything | ||||
|     if ($request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command | ||||
|         @nodes = (); | ||||
|         my @hostinfo = xCAT::NetworkUtils->determinehostname(); | ||||
|         my $cur_xmaster = pop @hostinfo; | ||||
|         xCAT::MsgUtils->trace(0, "d", "grub2: running on $cur_xmaster"); | ||||
|  | ||||
|         # Get current server managed node list | ||||
|         my $sn_hash = xCAT::ServiceNodeUtils->getSNformattedhash(\@rnodes, "xcat", "MN"); | ||||
|         my %managed = {}; | ||||
|         foreach (@{ $sn_hash->{$cur_xmaster} }) { $managed{$_} = 1; } | ||||
|  | ||||
|         foreach (@rnodes) { | ||||
|             if (xCAT::NetworkUtils->nodeonmynet($_)) { | ||||
|                 push @nodes, $_; | ||||
|     if ($args[0] eq 'stat') { | ||||
|         my $noderestab = xCAT::Table->new('noderes'); #in order to detect per-node tftp directories | ||||
|         my %nrhash = %{ $noderestab->getNodesAttribs(\@rnodes, [qw(tftpdir)]) }; | ||||
|         foreach my $node (@rnodes) { | ||||
|             my %response; | ||||
|             my $tftpdir; | ||||
|             if ($nrhash{$node}->[0] and $nrhash{$node}->[0]->{tftpdir}) { | ||||
|                 $tftpdir = $nrhash{$node}->[0]->{tftpdir}; | ||||
|             } else { | ||||
|                 my $msg = "grub2 configuration file was not created for node [$_] because sharedtftp attribute is not set and the node is not on same network as this xcatmaster"; | ||||
|                 if ( $cur_xmaster ) { | ||||
|                     $msg .= ": $cur_xmaster"; | ||||
|                 } | ||||
|                 if ( exists( $managed{$_} ) ) { | ||||
|                     # report error when it is under my control but I cannot handle it. | ||||
|                     my $rsp; | ||||
|                     $rsp->{data}->[0] = $msg; | ||||
|                     xCAT::MsgUtils->message("E", $rsp, $callback); | ||||
|                 } else { | ||||
|                     xCAT::MsgUtils->message("S", $msg); | ||||
|                 } | ||||
|                 $tftpdir = $globaltftpdir; | ||||
|             } | ||||
|             $response{node}->[0]->{name}->[0] = $node; | ||||
|             $response{node}->[0]->{data}->[0] = getstate($node, $tftpdir); | ||||
|             $callback->(\%response); | ||||
|         } | ||||
|     } else { | ||||
|         @nodes = @rnodes; | ||||
|     } | ||||
|  | ||||
|     #>>>>>>>used for trace log>>>>>>> | ||||
|     my $str_node = join(" ", @nodes); | ||||
|     xCAT::MsgUtils->trace($verbose_on_off, "d", "grub2: nodes are $str_node"); | ||||
|  | ||||
|     # return directly if no nodes in the same network | ||||
|     unless (@nodes) { | ||||
|         xCAT::MsgUtils->message("S", "xCAT: grub2 netboot: no valid nodes. Stop the operation on this server."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (ref($request->{arg})) { | ||||
|         @args = @{ $request->{arg} }; | ||||
|     my @nodes = (); | ||||
|     # Filter those nodes which have bad DNS: not resolvable or inconsistent IP | ||||
|     my %failurenodes = (); | ||||
|     my %preparednodes = (); | ||||
|     foreach (@rnodes) { | ||||
|         my $ipret = xCAT::NetworkUtils->checkNodeIPaddress($_); | ||||
|         my $errormsg = $ipret->{'error'}; | ||||
|         my $nodeip = $ipret->{'ip'}; | ||||
|         if ($errormsg) {# Add the node to failure set | ||||
|             xCAT::MsgUtils->trace(0, "E", "grub2: Defined IP address of $_ is $nodeip. $errormsg"); | ||||
|             unless ($nodeip) { | ||||
|                 $failurenodes{$_} = 1; | ||||
|             } | ||||
|         } | ||||
|         if ($nodeip) { | ||||
|             $preparednodes{$_} = $nodeip; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #if not shared tftpdir, then filter, otherwise, set up everything | ||||
|     if ($request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command | ||||
|         # Filter those nodes not in the same subnet, and print error message in log file. | ||||
|         foreach (keys %preparednodes) { | ||||
|             # Only handle its boot configuration files if the node in same subnet | ||||
|             if (xCAT::NetworkUtils->nodeonmynet($preparednodes{$_})) { | ||||
|                 push @nodes, $_; | ||||
|             } else { | ||||
|                 xCAT::MsgUtils->trace(0, "W", "grub2: configuration file was not created for [$_] because the node is not on the same network as this server"); | ||||
|                 delete $preparednodes{$_}; | ||||
|             } | ||||
|         } | ||||
|     } else { | ||||
|         @args = ($request->{arg}); | ||||
|         @nodes = keys %preparednodes; | ||||
|     } | ||||
|  | ||||
|     my $str_node = join(" ", @nodes); | ||||
|     xCAT::MsgUtils->trace($verbose_on_off, "d", "grub2: nodes are $str_node") if ($str_node); | ||||
|  | ||||
|     # Return directly if no nodes in the same network, need to report error on console if its managed nodes are not handled. | ||||
|     unless (@nodes) { | ||||
|         xCAT::MsgUtils->message("S", "xCAT: grub2 netboot: no valid nodes. Stop the operation on this server."); | ||||
|  | ||||
|         # If non-shared tftproot and non disjoint mode, need to figure out if no nodes here is a normal case. | ||||
|         if ($request->{'_disparatetftp'}->[0] && $request->{'_disjointmode'}->[0] != 1) { | ||||
|             # Find out which nodes are really mine only when not sharedtftp and not disjoint mode. | ||||
|             my %iphash   = (); | ||||
|             # flag the IPs or names in iphash | ||||
|             foreach (@hostinfo) { $iphash{$_} = 1; } | ||||
|  | ||||
|             # Get managed node list under current server | ||||
|             # The node will be under under 'site.master' if no 'noderes.servicenode' is defined | ||||
|             my $sn_hash = xCAT::ServiceNodeUtils->getSNformattedhash(\@rnodes, "xcat", "MN"); | ||||
|             my $req2manage = 0; | ||||
|             foreach (keys %$sn_hash) { | ||||
|                 if (exists($iphash{$_})) { | ||||
|                     $req2manage = 1; | ||||
|                     last; | ||||
|                 } | ||||
|             } | ||||
|             # Okay, now report error as no nodes are handled. | ||||
|             if ($req2manage == 0) { | ||||
|                 xCAT::MsgUtils->trace(0, "d", "grub2: No nodes are required to be managed on this server"); | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|         my $rsp; | ||||
|         $rsp->{errorcode}->[0] = 1; | ||||
|         $rsp->{error}->[0]     = "Failed to generate grub2 configurations for some node(s) on $::myxcatname. Check xCAT log file for more details."; | ||||
|         $callback->($rsp); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     #now run the begin part of the prescripts | ||||
|     unless ($args[0] eq 'stat') {    # or $args[0] eq 'enact') { | ||||
|     unless ($args[0] eq '') {    # or $args[0] eq 'enact') { | ||||
|         $errored = 0; | ||||
|         if ($request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handles my own children | ||||
|             xCAT::MsgUtils->trace($verbose_on_off, "d", "grub2: the call is distrubuted to the service node already, so only need to handles my own children"); | ||||
|         if ($request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handle my own children | ||||
|             xCAT::MsgUtils->trace($verbose_on_off, "d", "grub2: the call is distrubuted to the service node already, so only need to handle my own children"); | ||||
|             xCAT::MsgUtils->trace($verbose_on_off, "d", "grub2: issue runbeginpre request"); | ||||
|             $sub_req->({ command => ['runbeginpre'], | ||||
|                     node => \@nodes, | ||||
| @@ -609,7 +676,7 @@ sub process_request { | ||||
|     if (!$inittime) { $inittime = 0; } | ||||
|  | ||||
|     my %bphash; | ||||
|     unless ($args[0] eq 'stat') {    # or $args[0] eq 'enact') { | ||||
|     unless ($args[0] eq '') {    # or $args[0] eq 'enact') { | ||||
|         $errored = 0; | ||||
|         xCAT::MsgUtils->trace($verbose_on_off, "d", "grub2: issue setdestiny request"); | ||||
|         $sub_req->({ command => ['setdestiny'], | ||||
| @@ -619,11 +686,12 @@ sub process_request { | ||||
|                 bootparams => \%bphash | ||||
|                 }, \&pass_along); | ||||
|         if ($errored) {  | ||||
|             xCAT::MsgUtils->trace($verbose_on_off, "d", "petitboot: Failed in processing setdestiny.  Processing will not continue."); | ||||
|             xCAT::MsgUtils->trace($verbose_on_off, "d", "grub2: Failed in processing setdestiny.  Processing will not continue."); | ||||
|             return;  | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     xCAT::MsgUtils->trace($verbose_on_off, "d", "grub2: starting to handle configuration..."); | ||||
|     my $chaintab = xCAT::Table->new('chain', -create => 1); | ||||
|     my $chainhash = $chaintab->getNodesAttribs(\@nodes, ['currstate']); | ||||
|     my $noderestab = xCAT::Table->new('noderes', -create => 1); | ||||
| @@ -649,10 +717,7 @@ sub process_request { | ||||
|             $tftpdir = $globaltftpdir; | ||||
|         } | ||||
|         $response{node}->[0]->{name}->[0] = $_; | ||||
|         if ($args[0] eq 'stat') { | ||||
|             $response{node}->[0]->{data}->[0] = getstate($_, $tftpdir); | ||||
|             $callback->(\%response); | ||||
|         } elsif ($args[0]) { #If anything else, send it on to the destiny plugin, then setstate | ||||
|         if ($args[0]) { # Send it on to the destiny plugin, then setstate | ||||
|             my $ent          = $typehash->{$_}->[0]; | ||||
|             my $osimgname    = $ent->{'provmethod'}; | ||||
|             my $linuximghash = undef; | ||||
| @@ -668,11 +733,11 @@ sub process_request { | ||||
|             } | ||||
|         } | ||||
|     }    # end of foreach node | ||||
|     xCAT::MsgUtils->trace($verbose_on_off, "d", "grub2: Finish to handle configurations"); | ||||
|  | ||||
|     my @normalnodeset = keys %normalnodes; | ||||
|     my @breaknetboot  = keys %breaknetbootnodes; | ||||
|  | ||||
|     #print "grub2 :inittime=$inittime; normalnodeset=@normalnodeset; breaknetboot=@breaknetboot\n"; | ||||
|     my %osimagenodehash; | ||||
|     for my $nn (@normalnodeset) { | ||||
|  | ||||
| @@ -693,7 +758,7 @@ sub process_request { | ||||
|     } | ||||
|  | ||||
|     #Don't bother to try dhcp binding changes if sub_req not passed, i.e. service node build time | ||||
|     unless (($args[0] eq 'stat') || ($inittime) || ($args[0] eq 'offline')) { | ||||
|     unless (($inittime) || ($args[0] eq 'offline')) { | ||||
|         foreach my $osimage (keys %osimagenodehash) { | ||||
|  | ||||
|             #TOTO check the existence of grub2 executable files for corresponding arch | ||||
| @@ -793,7 +858,7 @@ sub process_request { | ||||
|     } | ||||
|  | ||||
|     #now run the end part of the prescripts | ||||
|     unless ($args[0] eq 'stat') {    # or $args[0] eq 'enact') | ||||
|     unless ($args[0] eq '') {    # or $args[0] eq 'enact') | ||||
|         $errored = 0; | ||||
|         if ($request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handles my own children | ||||
|             xCAT::MsgUtils->trace($verbose_on_off, "d", "grub2: issue runendpre request"); | ||||
| @@ -814,6 +879,16 @@ sub process_request { | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     # Return error codes if there are failed nodes | ||||
|     if (%failurenodes) { | ||||
|         my $rsp; | ||||
|         $rsp->{errorcode}->[0] = 1; | ||||
|         $rsp->{error}->[0]     = "Failed to generate grub2 configurations for some node(s) on $::myxcatname. Check xCAT log file for more details."; | ||||
|         $callback->($rsp); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| #---------------------------------------------------------------------------- | ||||
|   | ||||
| @@ -78,7 +78,7 @@ sub setstate { | ||||
|  | ||||
| =pod | ||||
|  | ||||
|   This function will manipulate the yaboot structure to match what the noderes/chain tables indicate the node should be booting. | ||||
|   This function will manipulate the petitboot structure to match what the noderes/chain tables indicate the node should be booting. | ||||
|  | ||||
| =cut | ||||
|  | ||||
| @@ -125,12 +125,10 @@ sub setstate { | ||||
|  | ||||
|                     # We are in the service node pools, print error if no facing ip. | ||||
|                     if (xCAT::InstUtils->is_me($sn)) { | ||||
|                         my @myself = xCAT::NetworkUtils->determinehostname(); | ||||
|                         my $myname = $myself[ (scalar @myself) - 1 ]; | ||||
|                         $::callback->( | ||||
|                             { | ||||
|                                 error => [ | ||||
|                                     "$myname: $ipfnd[1] on service node $sn" | ||||
|                                     "$::myxcatname: $ipfnd[1] on service node $sn" | ||||
|                                 ], | ||||
|                                 errorcode => [1] | ||||
|                             } | ||||
| @@ -142,7 +140,7 @@ sub setstate { | ||||
|                 $::callback->( | ||||
|                     { | ||||
|                         error => [ | ||||
|                             "$myname: $ipfnd[1]" | ||||
|                             "$::myxcatname: $ipfnd[1]" | ||||
|                         ], | ||||
|                         errorcode => [1] | ||||
|                     } | ||||
| @@ -170,18 +168,19 @@ sub setstate { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     my $pcfg; | ||||
|     unless (-d "$tftpdir/petitboot") { | ||||
|         mkpath("$tftpdir/petitboot"); | ||||
|     my $bootloader_root = "$tftpdir/petitboot"; | ||||
|     unless (-d "$bootloader_root") { | ||||
|         mkpath("$bootloader_root"); | ||||
|     } | ||||
|     my $nodemac; | ||||
|  | ||||
|     my $cref = $chainhash{$node}->[0]; #$chaintab->getNodeAttribs($node,['currstate']); | ||||
|  | ||||
|     my $pcfg; | ||||
|     # remove the old boot configuration file and create a new one, but only if not offline directive | ||||
|     unlink($tftpdir . "/petitboot/" . $node); | ||||
|     unlink("$bootloader_root/" . $node); | ||||
|     if ($cref and $cref->{currstate} ne "offline") { | ||||
|         open($pcfg, '>', $tftpdir . "/petitboot/" . $node); | ||||
|         open($pcfg, '>', "$bootloader_root/" . $node); | ||||
|         print $pcfg "#" . $cref->{currstate} . "\n"; | ||||
|     } | ||||
|     $normalnodes{$node} = 1;   #Assume a normal netboot (well, normal dhcp, | ||||
| @@ -217,18 +216,13 @@ sub setstate { | ||||
|             print $pcfg "\tappend \"" . $kern->{kcmdline} . "\"\n"; | ||||
|         } | ||||
|         close($pcfg); | ||||
|         my $inetn = xCAT::NetworkUtils->getipaddr($node); | ||||
|         unless ($inetn) { | ||||
|             syslog("local1|err", "xCAT unable to resolve IP for $node in petitboot plugin"); | ||||
|             return; | ||||
|         } | ||||
|     } else {    #TODO: actually, should possibly default to xCAT image? | ||||
|                 #print $pcfg "bye\n"; | ||||
|         close($pcfg); | ||||
|     } | ||||
|     my $ip = xCAT::NetworkUtils->getipaddr($node); | ||||
|     unless ($ip) { | ||||
|         syslog("local1|err", "xCAT unable to resolve IP in petitboot plugin"); | ||||
|         syslog("local1|err", "xCAT unable to resolve IP for $node in petitboot plugin"); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| @@ -237,9 +231,9 @@ sub setstate { | ||||
|     $pname = uc($pname); | ||||
|  | ||||
|     # remove the old boot configuration file and copy (link) a new one, but only if not offline directive | ||||
|     unlink($tftpdir . "/" . $pname); | ||||
|     unlink("$tftpdir/" . $pname); | ||||
|     if ($cref and $cref->{currstate} ne "offline") { | ||||
|         link($tftpdir . "/petitboot/" . $node, $tftpdir . "/" . $pname); | ||||
|         link("$bootloader_root/" . $node, "$tftpdir/" . $pname); | ||||
|     } | ||||
|     return; | ||||
| } | ||||
| @@ -283,12 +277,14 @@ sub preprocess_request { | ||||
|  | ||||
|     #use Getopt::Long; | ||||
|     my $HELP; | ||||
|     my $ALLFLAG; | ||||
|     my $VERSION; | ||||
|     my $VERBOSE; | ||||
|     Getopt::Long::Configure("bundling"); | ||||
|     Getopt::Long::Configure("pass_through"); | ||||
|     if (!GetOptions('h|?|help' => \$HELP, | ||||
|             'v|version' => \$VERSION, | ||||
|             'a'           =>\$ALLFLAG, | ||||
|             'V'         => \$VERBOSE    #>>>>>>>used for trace log>>>>>>> | ||||
|         )) { | ||||
|         if ($usage{$command}) { | ||||
| @@ -334,6 +330,13 @@ sub preprocess_request { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if ($ARGV[0] ne "stat" && $ALLFLAG) { | ||||
|         my %rsp; | ||||
|         $rsp{error}->[0] = "'-a' could only be used with 'stat' subcommand."; | ||||
|         $rsp{errorcode}->[0] = 1; | ||||
|         $callback1->(\%rsp); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     #Assume shared tftp directory for boring people, but for cool people, help sync up tftpdirectory contents when | ||||
|     #if they specify no sharedtftp in site table | ||||
| @@ -346,23 +349,55 @@ sub preprocess_request { | ||||
|         my @SN; | ||||
|         my @CN; | ||||
|         xCAT::ServiceNodeUtils->getSNandCPnodes(\@$nodes, \@SN, \@CN); | ||||
|         if ((@SN > 0) && (@CN > 0)) {    # there are both SN and CN | ||||
|             my $rsp; | ||||
|             $rsp->{data}->[0] = | ||||
| "Nodeset was run with a noderange containing both service nodes and compute nodes. This is not valid. You must submit with either compute nodes in the noderange or service nodes. \n"; | ||||
|             xCAT::MsgUtils->message("E", $rsp, $callback1); | ||||
|             return; | ||||
|  | ||||
|         unless (($args[0] eq 'stat') or ($args[0] eq 'enact')) { | ||||
|             if ((@SN > 0) && (@CN > 0)) {    # there are both SN and CN | ||||
|                 my %rsp; | ||||
|                 $rsp{errorcode}->[0] = 1; | ||||
|                 $rsp{error}->[0] = | ||||
|     "Nodeset was run with a noderange containing both service nodes and compute nodes. This is not valid. You must submit with either compute nodes in the noderange or service nodes. \n"; | ||||
|                 $callback1->(\%rsp); | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         $req->{'_disparatetftp'} = [1]; | ||||
|         if ($req->{inittime}->[0]) { | ||||
|             return [$req]; | ||||
|         } | ||||
|         if (@CN > 0) {    # if compute nodes broadcast to all servicenodes | ||||
|             return xCAT::Scope->get_broadcast_scope_with_parallel($req); | ||||
|         if (@CN > 0) {    # if compute nodes only, then broadcast to servic enodes | ||||
|  | ||||
|             my @sn = xCAT::ServiceNodeUtils->getSNList(); | ||||
|             unless ( @sn > 0 ) { | ||||
|                 return xCAT::Scope->get_parallel_scope($req) | ||||
|             } | ||||
|  | ||||
|             my $mynodeonly  = 0; | ||||
|             my @entries = xCAT::TableUtils->get_site_attribute("disjointdhcps"); | ||||
|             my $t_entry = $entries[0]; | ||||
|             if (defined($t_entry)) { | ||||
|                 $mynodeonly = $t_entry; | ||||
|             } | ||||
|             $req->{'_disjointmode'} = [$mynodeonly]; | ||||
|             xCAT::MsgUtils->trace(0, "d", "petitboot: disjointdhcps=$mynodeonly"); | ||||
|  | ||||
|             if ($mynodeonly == 0 || $ALLFLAG) { # broadcast to all service nodes | ||||
|                 return xCAT::Scope->get_broadcast_scope_with_parallel($req, \@sn); | ||||
|             } | ||||
|  | ||||
|             my $sn_hash = xCAT::ServiceNodeUtils->getSNformattedhash(\@CN, "xcat", "MN"); | ||||
|             my @dhcpsvrs = (); | ||||
|             my $ntab = xCAT::Table->new('networks'); | ||||
|             if ($ntab) { | ||||
|                 foreach (@{ $ntab->getAllEntries() }) { | ||||
|                     next unless ($_->{dynamicrange}); | ||||
|                     # if dynamicrange specified but dhcpserver was not - issue error message | ||||
|                     push @dhcpsvrs, $_->{dhcpserver} if ($_->{dhcpserver}) | ||||
|                 } | ||||
|             } | ||||
|             return xCAT::Scope->get_broadcast_disjoint_scope_with_parallel($req, $sn_hash, \@dhcpsvrs); | ||||
|         } | ||||
|     } | ||||
|     # Do not dispatch to service nodes if non-sharedtftp or the node range contains only SNs. | ||||
|     return xCAT::Scope->get_parallel_scope($req); | ||||
| } | ||||
|  | ||||
| @@ -374,16 +409,16 @@ sub process_request { | ||||
|     $sub_req    = shift; | ||||
|     my $command = $request->{command}->[0]; | ||||
|     %breaknetbootnodes = (); | ||||
|     %normalnodes       = (); | ||||
|     %normalnodes       = (); # It will be fill-up by method: setstate. | ||||
|  | ||||
|     #>>>>>>>used for trace log start>>>>>>> | ||||
|     my @args = (); | ||||
|     my %opt; | ||||
|     my $verbose_on_off = 0; | ||||
|     if (ref($::request->{arg})) { | ||||
|         @args = @{ $::request->{arg} }; | ||||
|     if (ref($request->{arg})) { | ||||
|         @args = @{ $request->{arg} }; | ||||
|     } else { | ||||
|         @args = ($::request->{arg}); | ||||
|         @args = ($request->{arg}); | ||||
|     } | ||||
|     @ARGV = @args; | ||||
|     GetOptions('V' => \$opt{V}); | ||||
| @@ -394,7 +429,9 @@ sub process_request { | ||||
|     if ($::XCATSITEVALS{"httpmethod"}) { $httpmethod = $::XCATSITEVALS{"httpmethod"}; } | ||||
|     if ($::XCATSITEVALS{"httpport"}) { $httpport = $::XCATSITEVALS{"httpport"}; } | ||||
|  | ||||
|     my @nodes; | ||||
|     my @hostinfo = xCAT::NetworkUtils->determinehostname(); | ||||
|     $::myxcatname = $hostinfo[-1]; | ||||
|     xCAT::MsgUtils->trace($verbose_on_off, "d", "petitboot: running on $::myxcatname"); | ||||
|     my @rnodes; | ||||
|     if (ref($request->{node})) { | ||||
|         @rnodes = @{ $request->{node} }; | ||||
| @@ -408,61 +445,101 @@ sub process_request { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     #if not shared tftpdir, then filter, otherwise, set up everything | ||||
|     if ($request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command | ||||
|         @nodes = (); | ||||
|         my @hostinfo = xCAT::NetworkUtils->determinehostname(); | ||||
|         my $cur_xmaster = pop @hostinfo; | ||||
|         xCAT::MsgUtils->trace(0, "d", "petitboot: running on $cur_xmaster"); | ||||
|  | ||||
|         # Get current server managed node list | ||||
|         my $sn_hash = xCAT::ServiceNodeUtils->getSNformattedhash(\@rnodes, "xcat", "MN"); | ||||
|         my %managed = {}; | ||||
|         foreach (@{ $sn_hash->{$cur_xmaster} }) { $managed{$_} = 1; } | ||||
|  | ||||
|         foreach (@rnodes) { | ||||
|             if (xCAT::NetworkUtils->nodeonmynet($_)) { | ||||
|                 push @nodes, $_; | ||||
|     if ($args[0] eq 'stat') { | ||||
|         my $noderestab = xCAT::Table->new('noderes'); #in order to detect per-node tftp directories | ||||
|         my %nrhash = %{ $noderestab->getNodesAttribs(\@rnodes, [qw(tftpdir)]) }; | ||||
|         foreach my $node (@rnodes) { | ||||
|             my %response; | ||||
|             my $tftpdir; | ||||
|             if ($nrhash{$node}->[0] and $nrhash{$node}->[0]->{tftpdir}) { | ||||
|                 $tftpdir = $nrhash{$node}->[0]->{tftpdir}; | ||||
|             } else { | ||||
|                 my $msg = "petitboot configuration file was not created for node [$_] because sharedtftp attribute is not set and the node is not on same network as this xcatmaster"; | ||||
|                 if ( $cur_xmaster ) { | ||||
|                     $msg .= ": $cur_xmaster"; | ||||
|                 } | ||||
|                 if ( exists( $managed{$_} ) ) { | ||||
|                     # report error when it is under my control but I cannot handle it. | ||||
|                     my $rsp; | ||||
|                     $rsp->{data}->[0] = $msg; | ||||
|                     xCAT::MsgUtils->message("E", $rsp, $callback); | ||||
|                 } else { | ||||
|                     xCAT::MsgUtils->message("S", $msg); | ||||
|                 } | ||||
|                 $tftpdir = $globaltftpdir; | ||||
|             } | ||||
|             $response{node}->[0]->{name}->[0] = $node; | ||||
|             $response{node}->[0]->{data}->[0] = getstate($node, $tftpdir); | ||||
|             $callback->(\%response); | ||||
|         } | ||||
|     } else { | ||||
|         @nodes = @rnodes; | ||||
|     } | ||||
|  | ||||
|     #>>>>>>>used for trace log>>>>>>> | ||||
|     my $str_node = join(" ", @nodes); | ||||
|     xCAT::MsgUtils->trace($verbose_on_off, "d", "petitboot: nodes are $str_node"); | ||||
|  | ||||
|     # return directly if no nodes in the same network | ||||
|     unless (@nodes) { | ||||
|         xCAT::MsgUtils->message("S", "xCAT: petitboot netboot: no valid nodes. Stop the operation on this server."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (ref($request->{arg})) { | ||||
|         @args = @{ $request->{arg} }; | ||||
|     my @nodes = (); | ||||
|     # Filter those nodes which have bad DNS: not resolvable or inconsistent IP | ||||
|     my %failurenodes = (); | ||||
|     my %preparednodes = (); | ||||
|     foreach (@rnodes) { | ||||
|         my $ipret = xCAT::NetworkUtils->checkNodeIPaddress($_); | ||||
|         my $errormsg = $ipret->{'error'}; | ||||
|         my $nodeip = $ipret->{'ip'}; | ||||
|         if ($errormsg) {# Add the node to failure set | ||||
|             xCAT::MsgUtils->trace(0, "E", "petitboot: Defined IP address of $_ is $nodeip. $errormsg"); | ||||
|             unless ($nodeip) { | ||||
|                 $failurenodes{$_} = 1; | ||||
|             } | ||||
|         } | ||||
|         if ($nodeip) { | ||||
|             $preparednodes{$_} = $nodeip; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #if not shared tftpdir, then filter, otherwise, set up everything | ||||
|     if ($request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command | ||||
|         # Filter those nodes not in the same subnet, and print error message in log file. | ||||
|         foreach (keys %preparednodes) { | ||||
|             # Only handle its boot configuration files if the node in same subnet | ||||
|             if (xCAT::NetworkUtils->nodeonmynet($preparednodes{$_})) { | ||||
|                 push @nodes, $_; | ||||
|             } else { | ||||
|                 xCAT::MsgUtils->trace(0, "W", "petitboot: configuration file was not created for [$_] because the node is not on the same network as this server"); | ||||
|                 delete $preparednodes{$_}; | ||||
|             } | ||||
|         } | ||||
|     } else { | ||||
|         @args = ($request->{arg}); | ||||
|         @nodes = keys %preparednodes; | ||||
|     } | ||||
|  | ||||
|     my $str_node = join(" ", @nodes); | ||||
|     xCAT::MsgUtils->trace($verbose_on_off, "d", "petitboot: nodes are $str_node") if ($str_node); | ||||
|  | ||||
|     # Return directly if no nodes in the same network, need to report error on console if its managed nodes are not handled. | ||||
|     unless (@nodes) { | ||||
|         xCAT::MsgUtils->message("S", "xCAT: petitboot netboot: no valid nodes. Stop the operation on this server."); | ||||
|  | ||||
|         # If non-shared tftproot and non disjoint mode, need to figure out if no nodes here is a normal case. | ||||
|         if ($request->{'_disparatetftp'}->[0] && $request->{'_disjointmode'}->[0] != 1) { | ||||
|             # Find out which nodes are really mine only when not sharedtftp and not disjoint mode. | ||||
|             my %iphash   = (); | ||||
|             # flag the IPs or names in iphash | ||||
|             foreach (@hostinfo) { $iphash{$_} = 1; } | ||||
|  | ||||
|             # Get managed node list under current server | ||||
|             # The node will be under under 'site.master' if no 'noderes.servicenode' is defined | ||||
|             my $sn_hash = xCAT::ServiceNodeUtils->getSNformattedhash(\@rnodes, "xcat", "MN"); | ||||
|             my $req2manage = 0; | ||||
|             foreach (keys %$sn_hash) { | ||||
|                 if (exists($iphash{$_})) { | ||||
|                     $req2manage = 1; | ||||
|                     last; | ||||
|                 } | ||||
|             } | ||||
|             if ($req2manage == 0) { | ||||
|                 #No nodes are required to be handled, quit without error. | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|         # Okay, now report error as no nodes are handled. | ||||
|         my $rsp; | ||||
|         $rsp->{errorcode}->[0] = 1; | ||||
|         $rsp->{error}->[0]     = "Failed to generate petitboot configurations for some node(s) on $::myxcatname. Check xCAT log file for more details."; | ||||
|         $callback->($rsp); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     #now run the begin part of the prescripts | ||||
|     unless ($args[0] eq 'stat') {    # or $args[0] eq 'enact') { | ||||
|     unless ($args[0] eq '') {    # or $args[0] eq 'enact') { | ||||
|         $errored = 0; | ||||
|         if ($request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handles my own children | ||||
|             xCAT::MsgUtils->trace($verbose_on_off, "d", "petitboot: the call is distrubuted to the service node already, so only need to handles my own children"); | ||||
|         if ($request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handle my own children | ||||
|             xCAT::MsgUtils->trace($verbose_on_off, "d", "petitboot: the call is distrubuted to the service node already, so only need to handle my own children"); | ||||
|             xCAT::MsgUtils->trace($verbose_on_off, "d", "petitboot: issue runbeginpre request"); | ||||
|             $sub_req->({ command => ['runbeginpre'], | ||||
|                     node => \@nodes, | ||||
| @@ -471,7 +548,7 @@ sub process_request { | ||||
|             xCAT::MsgUtils->trace($verbose_on_off, "d", "petitboot: nodeset did not distribute to the service node"); | ||||
|             xCAT::MsgUtils->trace($verbose_on_off, "d", "petitboot: issue runbeginpre request"); | ||||
|             $sub_req->({ command => ['runbeginpre'], | ||||
|                     node => \@rnodes, | ||||
|                     node => \@nodes, | ||||
|                     arg => [ $args[0] ] }, \&pass_along); | ||||
|         } | ||||
|         if ($errored) { | ||||
| @@ -489,7 +566,7 @@ sub process_request { | ||||
|     if (!$inittime) { $inittime = 0; } | ||||
|  | ||||
|     my %bphash; | ||||
|     unless ($args[0] eq 'stat') {    # or $args[0] eq 'enact') { | ||||
|     unless ($args[0] eq '') {    # or $args[0] eq 'enact') { | ||||
|         $errored = 0; | ||||
|         xCAT::MsgUtils->trace($verbose_on_off, "d", "petitboot: issue setdestiny request"); | ||||
|         $sub_req->({ command => ['setdestiny'], | ||||
| @@ -515,6 +592,8 @@ sub process_request { | ||||
|                 }); | ||||
|         xCAT::MsgUtils->message("S", "xCAT: petitboot netboot: clear node(s): @nodes boot device setting."); | ||||
|     } | ||||
|  | ||||
|     xCAT::MsgUtils->trace($verbose_on_off, "d", "petitboot: starting to handle configuration..."); | ||||
|     my $chaintab = xCAT::Table->new('chain', -create => 1); | ||||
|     my $chainhash = $chaintab->getNodesAttribs(\@nodes, ['currstate']); | ||||
|     my $noderestab = xCAT::Table->new('noderes', -create => 1); | ||||
| @@ -538,13 +617,10 @@ sub process_request { | ||||
|             $tftpdir = $globaltftpdir; | ||||
|         } | ||||
|         $response{node}->[0]->{name}->[0] = $_; | ||||
|         if ($args[0] eq 'stat') { | ||||
|             $response{node}->[0]->{data}->[0] = getstate($_, $tftpdir); | ||||
|             $callback->(\%response); | ||||
|         } elsif ($args[0]) { #If anything else, send it on to the destiny plugin, then setstate | ||||
|         if ($args[0]) { # send it on to the destiny plugin, then setstate | ||||
|             my $ent       = $typehash->{$_}->[0]; | ||||
|             my $osimgname = $ent->{'provmethod'}; | ||||
|             my $linuximghash = $linuximghash = $linuximgtab->getAttribs({ imagename => $osimgname }, 'boottarget', 'addkcmdline'); | ||||
|             my $linuximghash = $linuximgtab->getAttribs({ imagename => $osimgname }, 'boottarget', 'addkcmdline'); | ||||
|  | ||||
|  | ||||
|             ($rc, $errstr) = setstate($_, \%bphash, $chainhash, $machash, $tftpdir, $nodereshash, $linuximghash); | ||||
| @@ -555,11 +631,10 @@ sub process_request { | ||||
|             } | ||||
|         } | ||||
|     }    # end of foreach node | ||||
|     xCAT::MsgUtils->trace($verbose_on_off, "d", "petitboot: Finish to handle configurations"); | ||||
|  | ||||
|     my @normalnodeset = keys %normalnodes; | ||||
|     my @breaknetboot  = keys %breaknetbootnodes; | ||||
|  | ||||
|     #print "yaboot:inittime=$inittime; normalnodeset=@normalnodeset; breaknetboot=@breaknetboot\n"; | ||||
|     my %osimagenodehash; | ||||
|     for my $nn (@normalnodeset) { | ||||
|  | ||||
| @@ -570,7 +645,7 @@ sub process_request { | ||||
|     } | ||||
|  | ||||
|     #Don't bother to try dhcp binding changes if sub_req not passed, i.e. service node build time | ||||
|     unless (($args[0] eq 'stat') || ($inittime) || ($args[0] eq 'offline')) { | ||||
|     unless (($inittime) || ($args[0] eq 'offline')) { | ||||
|  | ||||
|         #dhcp stuff | ||||
|         my $do_dhcpsetup = 1; | ||||
| @@ -580,16 +655,17 @@ sub process_request { | ||||
|             if ($t_entry =~ /0|n|N/) { $do_dhcpsetup = 0; } | ||||
|         } | ||||
|         if ($do_dhcpsetup) { | ||||
|             if ($::request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command | ||||
|                 xCAT::MsgUtils->trace($verbose_on_off, "d", "petitboot: issue makedhcp request"); | ||||
|                 $sub_req->({ command => ['makedhcp'], arg => ['-l'], | ||||
|                         node => \@normalnodeset }, $callback); | ||||
|             } else { | ||||
|                 xCAT::MsgUtils->trace($verbose_on_off, "d", "petitboot: issue makedhcp request"); | ||||
|                 $sub_req->({ command => ['makedhcp'], | ||||
|                         node => \@normalnodeset }, $callback); | ||||
|             } | ||||
|             my @parameter; | ||||
|             push @parameter, '-l' if ($::request->{'_disparatetftp'}->[0]); | ||||
|             xCAT::MsgUtils->trace($verbose_on_off, "d", "petitboot: issue makedhcp request"); | ||||
|  | ||||
|             $sub_req->({ command => ['makedhcp'], | ||||
|                          arg => \@parameter, | ||||
|                          node => \@normalnodeset }, $callback); | ||||
|         } else { | ||||
|             xCAT::MsgUtils->trace($verbose_on_off, "d", "petitboot: dhcpsetup=$do_dhcpsetup"); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     if ($args[0] eq 'offline') { | ||||
| @@ -599,7 +675,7 @@ sub process_request { | ||||
|     } | ||||
|  | ||||
|     #now run the end part of the prescripts | ||||
|     unless ($args[0] eq 'stat') {    # or $args[0] eq 'enact') | ||||
|     unless ($args[0] eq '') {    # or $args[0] eq 'enact') | ||||
|         $errored = 0; | ||||
|         if ($request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handles my own children | ||||
|             xCAT::MsgUtils->trace($verbose_on_off, "d", "petitboot: issue runendpre request"); | ||||
| @@ -609,7 +685,7 @@ sub process_request { | ||||
|         } else { #nodeset did not distribute to the service node, here we need to let runednpre to distribute the nodes to their masters | ||||
|             xCAT::MsgUtils->trace($verbose_on_off, "d", "petitboot: issue runendpre request"); | ||||
|             $sub_req->({ command => ['runendpre'], | ||||
|                     node => \@rnodes, | ||||
|                     node => \@nodes, | ||||
|                     arg => [ $args[0] ] }, \&pass_along); | ||||
|         } | ||||
|         if ($errored) { | ||||
| @@ -620,6 +696,15 @@ sub process_request { | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     # Return error codes if there are failed nodes | ||||
|     if (%failurenodes) { | ||||
|         my $rsp; | ||||
|         $rsp->{errorcode}->[0] = 1; | ||||
|         $rsp->{error}->[0]     = "Failed to generate petitboot configurations for some node(s) on $::myxcatname. Check xCAT log file for more details."; | ||||
|         $callback->($rsp); | ||||
|         return; | ||||
|     } | ||||
| } | ||||
|  | ||||
| #---------------------------------------------------------------------------- | ||||
|   | ||||
| @@ -331,10 +331,12 @@ sub preprocess_request { | ||||
|     Getopt::Long::Configure("bundling"); | ||||
|     Getopt::Long::Configure("pass_through"); | ||||
|     my $HELP; | ||||
|     my $ALLFLAG; | ||||
|     my $VERSION; | ||||
|     my $VERBOSE; | ||||
|     if (!GetOptions('h|?|help' => \$HELP, | ||||
|             'v|version' => \$VERSION, | ||||
|             'a'           =>\$ALLFLAG, | ||||
|             'V'         => \$VERBOSE    #>>>>>>>used for trace log>>>>>>> | ||||
|         )) { | ||||
|         if ($usage{$command}) { | ||||
| @@ -380,6 +382,13 @@ sub preprocess_request { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if ($ARGV[0] ne "stat" && $ALLFLAG) { | ||||
|         my %rsp; | ||||
|         $rsp{error}->[0] = "'-a' could only be used with 'stat' subcommand."; | ||||
|         $rsp{errorcode}->[0] = 1; | ||||
|         $callback1->(\%rsp); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     #Assume shared tftp directory for boring people, but for cool people, help sync up tftpdirectory contents when | ||||
|     #they specify no sharedtftp in site table | ||||
| @@ -394,12 +403,12 @@ sub preprocess_request { | ||||
|         xCAT::ServiceNodeUtils->getSNandCPnodes(\@$nodes, \@SN, \@CN); | ||||
|         unless (($args[0] eq 'stat') or ($args[0] eq 'enact')) { # mix is ok for these options | ||||
|             if ((@SN > 0) && (@CN > 0)) {    # there are both SN and CN | ||||
|                 my $rsp; | ||||
|                 $rsp->{data}->[0] = | ||||
|                 my %rsp; | ||||
|                 $rsp{errorcode}->[0] = 1; | ||||
|                 $rsp{error}->[0] = | ||||
| "Nodeset was run with a noderange containing both service nodes and compute nodes. This is not valid. You must submit with either compute nodes in the noderange or service nodes. \n"; | ||||
|                 xCAT::MsgUtils->message("E", $rsp, $callback1); | ||||
|                 $callback1->(\%rsp); | ||||
|                 return; | ||||
|  | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @@ -408,9 +417,39 @@ sub preprocess_request { | ||||
|             return [$req]; | ||||
|         } | ||||
|         if (@CN > 0) {    # if compute nodes broadcast to all servicenodes | ||||
|             return xCAT::Scope->get_broadcast_scope_with_parallel($req); | ||||
|  | ||||
|             my @sn = xCAT::ServiceNodeUtils->getSNList(); | ||||
|             unless ( @sn > 0 ) { | ||||
|                 return xCAT::Scope->get_parallel_scope($req) | ||||
|             } | ||||
|  | ||||
|             my $mynodeonly  = 0; | ||||
|             my @entries = xCAT::TableUtils->get_site_attribute("disjointdhcps"); | ||||
|             my $t_entry = $entries[0]; | ||||
|             if (defined($t_entry)) { | ||||
|                 $mynodeonly = $t_entry; | ||||
|             } | ||||
|             $req->{'_disjointmode'} = [$mynodeonly]; | ||||
|             xCAT::MsgUtils->trace(0, "d", "xnba: disjointdhcps=$mynodeonly"); | ||||
|  | ||||
|             if ($mynodeonly == 0 || $ALLFLAG) { # broadcast to all service nodes | ||||
|                 return xCAT::Scope->get_broadcast_scope_with_parallel($req, \@sn); | ||||
|             } | ||||
|  | ||||
|             my $sn_hash = xCAT::ServiceNodeUtils->getSNformattedhash(\@CN, "xcat", "MN"); | ||||
|             my @dhcpsvrs = (); | ||||
|             my $ntab = xCAT::Table->new('networks'); | ||||
|             if ($ntab) { | ||||
|                 foreach (@{ $ntab->getAllEntries() }) { | ||||
|                     next unless ($_->{dynamicrange}); | ||||
|                     # if dynamicrange specified but dhcpserver was not - issue error message | ||||
|                     push @dhcpsvrs, $_->{dhcpserver} if ($_->{dhcpserver}) | ||||
|                 } | ||||
|             } | ||||
|             return xCAT::Scope->get_broadcast_disjoint_scope_with_parallel($req, $sn_hash, \@dhcpsvrs); | ||||
|         } | ||||
|     } | ||||
|     # Do not dispatch to service nodes if non-sharedtftp or the node range contains only SNs. | ||||
|     return xCAT::Scope->get_parallel_scope($req); | ||||
| } | ||||
|  | ||||
| @@ -437,12 +476,14 @@ sub process_request { | ||||
|  | ||||
|     #>>>>>>>used for trace log end>>>>>>> | ||||
|  | ||||
|     my @hostinfo = xCAT::NetworkUtils->determinehostname(); | ||||
|     $::myxcatname = $hostinfo[-1]; | ||||
|     xCAT::MsgUtils->trace(0, "d", "xnba: running on $::myxcatname"); | ||||
|     if (ref($::XNBA_request->{node})) { | ||||
|         @rnodes = @{ $::XNBA_request->{node} }; | ||||
|     } else { | ||||
|         if ($::XNBA_request->{node}) { @rnodes = ($::XNBA_request->{node}); } | ||||
|     } | ||||
|  | ||||
|     unless (@rnodes) { | ||||
|         if ($usage{ $::XNBA_request->{command}->[0] }) { | ||||
|             $::XNBA_callback->({ data => $usage{ $::XNBA_request->{command}->[0] } }); | ||||
| @@ -450,60 +491,98 @@ sub process_request { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     #if not shared, then help sync up | ||||
|     if ($::XNBA_request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command | ||||
|         @nodes = (); | ||||
|         my @hostinfo = xCAT::NetworkUtils->determinehostname(); | ||||
|         my $cur_xmaster = pop @hostinfo; | ||||
|         xCAT::MsgUtils->trace(0, "d", "xnba: running on $cur_xmaster"); | ||||
|          | ||||
|         # Get current server managed node list | ||||
|         my $sn_hash = xCAT::ServiceNodeUtils->getSNformattedhash(\@rnodes, "xcat", "MN"); | ||||
|         my %managed = {}; | ||||
|         foreach (@{ $sn_hash->{$cur_xmaster} }) { $managed{$_} = 1; } | ||||
|  | ||||
|         # Whatever the node managed by this xcatmaster explicitly, if the node in same subnet, we need to handle its boot configuration files | ||||
|         foreach (@rnodes) { | ||||
|             if (xCAT::NetworkUtils->nodeonmynet($_)) { | ||||
|                 push @nodes, $_; | ||||
|     if ($args[0] eq 'stat') { | ||||
|         my $noderestab = xCAT::Table->new('noderes'); #in order to detect per-node tftp directories | ||||
|         my %nrhash = %{ $noderestab->getNodesAttribs(\@rnodes, [qw(tftpdir)]) }; | ||||
|         foreach my $node (@rnodes) { | ||||
|             my %response; | ||||
|             my $tftpdir; | ||||
|             if ($nrhash{$node}->[0] and $nrhash{$node}->[0]->{tftpdir}) { | ||||
|                 $tftpdir = $nrhash{$node}->[0]->{tftpdir}; | ||||
|             } else { | ||||
|                 my $msg = "xnba configuration file was not created for node [$_] because sharedtftp attribute is not set and the node is not on same network as this xcatmaster"; | ||||
|                 if ( $cur_xmaster ) {  | ||||
|                     $msg .= ": $cur_xmaster";  | ||||
|                 } | ||||
|                 if ( exists( $managed{$_} ) ) { | ||||
|                     # report error when it is under my control but I cannot handle it. | ||||
|                     my $rsp; | ||||
|                     $rsp->{data}->[0] = $msg; | ||||
|                     xCAT::MsgUtils->message("E", $rsp, $::XNBA_callback); | ||||
|                 } else { | ||||
|                     xCAT::MsgUtils->message("S", $msg); | ||||
|                 } | ||||
|  | ||||
|                 $tftpdir = $globaltftpdir; | ||||
|             } | ||||
|             $response{node}->[0]->{name}->[0] = $node; | ||||
|             $response{node}->[0]->{data}->[0] = getstate($node, $tftpdir); | ||||
|             $::XNBA_callback->(\%response); | ||||
|         } | ||||
|     } else { | ||||
|         @nodes = @rnodes; | ||||
|     } | ||||
|  | ||||
|     #>>>>>>>used for trace log>>>>>>> | ||||
|     my $str_node = join(" ", @nodes); | ||||
|     xCAT::MsgUtils->trace(0, "d", "xnba: nodes are $str_node"); | ||||
|  | ||||
|     # return directly if no nodes in the same network | ||||
|     unless (@nodes) { | ||||
|         xCAT::MsgUtils->message("S", "xCAT: xnba netboot: no valid nodes. Stop the operation on this server."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (ref($::XNBA_request->{arg})) { | ||||
|         @args = @{ $::XNBA_request->{arg} }; | ||||
|     my @nodes = (); | ||||
|     # Filter those nodes which have bad DNS: not resolvable or inconsistent IP | ||||
|     my %failurenodes = (); | ||||
|     my %preparednodes = (); | ||||
|     foreach (@rnodes) { | ||||
|         my $ipret = xCAT::NetworkUtils->checkNodeIPaddress($_); | ||||
|         my $errormsg = $ipret->{'error'}; | ||||
|         my $nodeip = $ipret->{'ip'}; | ||||
|         if ($errormsg) {# Add the node to failure set | ||||
|             xCAT::MsgUtils->trace(0, "E", "xnba: Defined IP address of $_ is $nodeip. $errormsg"); | ||||
|             unless ($nodeip) { | ||||
|                 $failurenodes{$_} = 1; | ||||
|             } | ||||
|         } | ||||
|         if ($nodeip) { | ||||
|             $preparednodes{$_} = $nodeip; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #if not shared tftpdir, then filter, otherwise, set up everything | ||||
|     if ($::XNBA_request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command | ||||
|         # Filter those nodes not in the same subnet, and print error message in log file. | ||||
|         foreach (keys %preparednodes) { | ||||
|             # Only handle its boot configuration files if the node in same subnet | ||||
|             if (xCAT::NetworkUtils->nodeonmynet($preparednodes{$_})) { | ||||
|                 push @nodes, $_; | ||||
|             } else { | ||||
|                 xCAT::MsgUtils->trace(0, "W", "xnba: configuration file was not created for [$_] because the node is not on the same network as this server"); | ||||
|                 delete $preparednodes{$_}; | ||||
|             } | ||||
|         } | ||||
|     } else { | ||||
|         @args = ($::XNBA_request->{arg}); | ||||
|         @nodes = keys %preparednodes; | ||||
|     } | ||||
|  | ||||
|     my $str_node = join(" ", @nodes); | ||||
|     xCAT::MsgUtils->trace(0, "d", "xnba: nodes are $str_node") if ($str_node); | ||||
|  | ||||
|     # Return directly if no nodes in the same network, need to report error on console if its managed nodes are not handled. | ||||
|     unless (@nodes) { | ||||
|         xCAT::MsgUtils->message("S", "xCAT: xnba netboot: no valid nodes. Stop the operation on this server."); | ||||
|  | ||||
|         # If non-shared tftproot and non disjoint mode, need to figure out if no nodes here is a normal case. | ||||
|         if ($::XNBA_request->{'_disparatetftp'}->[0] && $::XNBA_request->{'_disjointmode'}->[0] != 1) { | ||||
|             # Find out which nodes are really mine only when not sharedtftp and not disjoint mode. | ||||
|             my %iphash   = (); | ||||
|             # flag the IPs or names in iphash | ||||
|             foreach (@hostinfo) { $iphash{$_} = 1; } | ||||
|  | ||||
|             # Get managed node list under current server | ||||
|             # The node will be under under 'site.master' if no 'noderes.servicenode' is defined | ||||
|             my $sn_hash = xCAT::ServiceNodeUtils->getSNformattedhash(\@rnodes, "xcat", "MN"); | ||||
|             my $req2manage = 0; | ||||
|             foreach (keys %$sn_hash) { | ||||
|                 if (exists($iphash{$_})) { | ||||
|                     $req2manage = 1; | ||||
|                     last; | ||||
|                 } | ||||
|             } | ||||
|             if ($req2manage == 0) { | ||||
|                 #No nodes are required to be handled, quit without error. | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|         # Okay, now report error as no nodes are handled. | ||||
|         my $rsp; | ||||
|         $rsp->{errorcode}->[0] = 1; | ||||
|         $rsp->{error}->[0]     = "Failed to generate xnba configurations for some node(s) on $::myxcatname. Check xCAT log file for more details."; | ||||
|         $::XNBA_callback->($rsp); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     #now run the begin part of the prescripts | ||||
|     unless ($args[0] eq 'stat') {    # or $args[0] eq 'enact') { | ||||
|     unless ($args[0] eq '') {    # or $args[0] eq 'enact') { | ||||
|         $errored = 0; | ||||
|         if ($::XNBA_request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handles my own children | ||||
|             xCAT::MsgUtils->trace($verbose_on_off, "d", "xnba: the call is distrubuted to the service node already, so only need to handles my own children"); | ||||
| @@ -515,7 +594,7 @@ sub process_request { | ||||
|             xCAT::MsgUtils->trace($verbose_on_off, "d", "xnba: nodeset did not distribute to the service node"); | ||||
|             xCAT::MsgUtils->trace($verbose_on_off, "d", "xnba: issue runbeginpre request"); | ||||
|             $sub_req->({ command => ['runbeginpre'], | ||||
|                     node => \@rnodes, | ||||
|                     node => \@nodes, | ||||
|                     arg => [ $args[0] ] }, \&pass_along); | ||||
|         } | ||||
|         if ($errored) { | ||||
| @@ -547,7 +626,7 @@ sub process_request { | ||||
|     if (!$inittime) { $inittime = 0; } | ||||
|  | ||||
|     my %bphash; | ||||
|     unless ($args[0] eq 'stat') {    # or $args[0] eq 'enact') { | ||||
|     unless ($args[0] eq '') {    # or $args[0] eq 'enact') { | ||||
|         $errored = 0; | ||||
|         xCAT::MsgUtils->trace($verbose_on_off, "d", "xnba: issue setdestiny request"); | ||||
|         $sub_req->({ command => ['setdestiny'], | ||||
| @@ -562,6 +641,7 @@ sub process_request { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     xCAT::MsgUtils->trace($verbose_on_off, "d", "xnba: starting to handle configuration..."); | ||||
|     #Time to actually configure the nodes, first extract database data with the scalable calls | ||||
|     my $chaintab = xCAT::Table->new('chain'); | ||||
|     my $noderestab = xCAT::Table->new('noderes'); #in order to detect per-node tftp directories | ||||
| @@ -589,10 +669,7 @@ sub process_request { | ||||
|         mkpath($tftpdir . "/xcat/xnba/nodes/"); | ||||
|         my %response; | ||||
|         $response{node}->[0]->{name}->[0] = $_; | ||||
|         if ($args[0] eq 'stat') { | ||||
|             $response{node}->[0]->{data}->[0] = getstate($_, $tftpdir); | ||||
|             $::XNBA_callback->(\%response); | ||||
|         } elsif ($args[0]) { #If anything else, send it on to the destiny plugin, then setstate | ||||
|         if ($args[0]) { # Send it on to the destiny plugin, then setstate | ||||
|             my $rc; | ||||
|             my $errstr; | ||||
|             my $ent          = $typehash->{$_}->[0]; | ||||
| @@ -617,45 +694,38 @@ sub process_request { | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     xCAT::MsgUtils->trace($verbose_on_off, "d", "xnba: Finish to handle configurations"); | ||||
|  | ||||
|     # for offline operation, remove the dhcp entries | ||||
|     if ($args[0] eq 'offline') { | ||||
|         $sub_req->({ command => ['makedhcp'], arg => ['-d'], node => \@nodes }, $::XNBA_callback); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     #dhcp stuff -- inittime is set when xcatd on sn is started | ||||
|     unless (($args[0] eq 'stat') || ($inittime) || ($args[0] eq 'offline')) { | ||||
|     unless (($inittime) || ($args[0] eq 'offline')) { | ||||
|         my $do_dhcpsetup = 1; | ||||
|  | ||||
|         #my $sitetab = xCAT::Table->new('site'); | ||||
|         #if ($sitetab) { | ||||
|         #(my $ref) = $sitetab->getAttribs({key => 'dhcpsetup'}, 'value'); | ||||
|         my @entries = xCAT::TableUtils->get_site_attribute("dhcpsetup"); | ||||
|         my $t_entry = $entries[0]; | ||||
|         if (defined($t_entry)) { | ||||
|             if ($t_entry =~ /0|n|N/) { $do_dhcpsetup = 0; } | ||||
|         } | ||||
|  | ||||
|         #} | ||||
|  | ||||
|         if ($do_dhcpsetup) { | ||||
|             if ($::XNBA_request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command | ||||
|                 xCAT::MsgUtils->trace($verbose_on_off, "d", "xnba: issue makedhcp request"); | ||||
|                 $sub_req->({ command => ['makedhcp'], arg => ['-l'], | ||||
|                         node => \@nodes }, $::XNBA_callback); | ||||
|             } else { | ||||
|                 xCAT::MsgUtils->trace($verbose_on_off, "d", "xnba: issue makedhcp request"); | ||||
|                 $sub_req->({ command => ['makedhcp'], | ||||
|                         node => \@nodes }, $::XNBA_callback); | ||||
|             } | ||||
|             my @parameter; | ||||
|             push @parameter, '-l' if ($::request->{'_disparatetftp'}->[0]); | ||||
|             xCAT::MsgUtils->trace($verbose_on_off, "d", "xnba: issue makedhcp request"); | ||||
|  | ||||
|             $sub_req->({ command => ['makedhcp'], | ||||
|                          arg => \@parameter, | ||||
|                          node => \@nodes }, $::XNBA_callback); | ||||
|         } else { | ||||
|             xCAT::MsgUtils->trace($verbose_on_off, "d", "xnba: dhcpsetup=$do_dhcpsetup"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #now run the end part of the prescripts | ||||
|     unless ($args[0] eq 'stat') {    # or $args[0] eq 'enact') | ||||
|     unless ($args[0] eq '') {    # or $args[0] eq 'enact') | ||||
|         $errored = 0; | ||||
|         if ($::XNBA_request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handles my own children | ||||
|         if ($::XNBA_request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handle my own children | ||||
|             xCAT::MsgUtils->trace($verbose_on_off, "d", "xnba: issue runendpre request"); | ||||
|             $sub_req->({ command => ['runendpre'], | ||||
|                     node => \@nodes, | ||||
| @@ -663,7 +733,7 @@ sub process_request { | ||||
|         } else { #nodeset did not distribute to the service node, here we need to let runednpre to distribute the nodes to their masters | ||||
|             xCAT::MsgUtils->trace($verbose_on_off, "d", "xnba: issue runendpre request"); | ||||
|             $sub_req->({ command => ['runendpre'], | ||||
|                     node => \@rnodes, | ||||
|                     node => \@nodes, | ||||
|                     arg => [ $args[0] ] }, \&pass_along); | ||||
|         } | ||||
|         if ($errored) { | ||||
| @@ -674,6 +744,15 @@ sub process_request { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     # Return error codes if there are failed nodes | ||||
|     if (%failurenodes) { | ||||
|         my $rsp; | ||||
|         $rsp->{errorcode}->[0] = 1; | ||||
|         $rsp->{error}->[0]     = "Failed to generate xnba configurations for some node(s) on $::myxcatname. Check xCAT log file for more details."; | ||||
|         $::XNBA_callback->($rsp); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user